Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use ref fields on .NET 7 for all span-like types #519

Merged
merged 5 commits into from
Dec 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,17 @@ namespace CommunityToolkit.HighPerformance.Enumerables;
/// <typeparam name="T">The type of items to enumerate.</typeparam>
public readonly ref struct ReadOnlyRefEnumerable<T>
{
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
/// <summary>
/// The <typeparamref name="T"/> reference for the <see cref="ReadOnlyRefEnumerable{T}"/> instance.
/// </summary>
private readonly ref readonly T reference;

/// <summary>
/// The length of the current sequence.
/// </summary>
private readonly int length;
#elif NETSTANDARD2_1_OR_GREATER
/// <summary>
/// The <see cref="ReadOnlySpan{T}"/> instance pointing to the first item in the target memory area.
/// </summary>
Expand Down Expand Up @@ -51,6 +61,7 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
private readonly int step;

#if NETSTANDARD2_1_OR_GREATER
#if !NET7_0_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct.
/// </summary>
Expand All @@ -59,9 +70,15 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ReadOnlyRefEnumerable(ReadOnlySpan<T> span, int step)
{
#if NET7_0_OR_GREATER
this.reference = ref MemoryMarshal.GetReference(span);
this.length = span.Length;
#else
this.span = span;
#endif
this.step = step;
}
#endif

/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct.
Expand All @@ -72,8 +89,14 @@ private ReadOnlyRefEnumerable(ReadOnlySpan<T> span, int step)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ReadOnlyRefEnumerable(in T reference, int length, int step)
{
#if NET7_0_OR_GREATER
this.reference = ref reference;
this.length = length;
this.step = step;
#else
this.span = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(reference), length);
this.step = step;
#endif
}

/// <summary>
Expand Down Expand Up @@ -124,7 +147,9 @@ internal ReadOnlyRefEnumerable(object? instance, IntPtr offset, int length, int
public int Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
get => this.length;
#elif NETSTANDARD2_1_OR_GREATER
get => this.span.Length;
#else
get => this.length;
Expand All @@ -149,7 +174,9 @@ public ref readonly T this[int index]
ThrowHelper.ThrowIndexOutOfRangeException();
}

#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
ref T r0 = ref Unsafe.AsRef(in this.reference);
#elif NETSTANDARD2_1_OR_GREATER
ref T r0 = ref MemoryMarshal.GetReference(this.span);
#else
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
Expand Down Expand Up @@ -181,7 +208,9 @@ public ref readonly T this[Index index]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator()
{
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
return new(in this.reference, this.length, this.step);
#elif NETSTANDARD2_1_OR_GREATER
return new(this.span, this.step);
#else
return new(this.instance, this.offset, this.length, this.step);
Expand All @@ -197,7 +226,26 @@ public Enumerator GetEnumerator()
/// </exception>
public void CopyTo(RefEnumerable<T> destination)
{
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
if (this.step == 1)
{
destination.CopyFrom(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in this.reference), this.length));

return;
}

if (destination.Step == 1)
{
CopyTo(MemoryMarshal.CreateSpan(ref destination.Reference, destination.Length));

return;
}

ref T sourceRef = ref Unsafe.AsRef(in this.reference);
ref T destinationRef = ref destination.Reference;
int sourceLength = this.length;
int destinationLength = destination.Length;
#elif NETSTANDARD2_1_OR_GREATER
if (this.step == 1)
{
destination.CopyFrom(this.span);
Expand Down Expand Up @@ -238,7 +286,10 @@ public void CopyTo(RefEnumerable<T> destination)
/// <returns>Whether or not the operation was successful.</returns>
public bool TryCopyTo(RefEnumerable<T> destination)
{
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
int sourceLength = this.length;
int destinationLength = destination.Length;
#elif NETSTANDARD2_1_OR_GREATER
int sourceLength = this.span.Length;
int destinationLength = destination.Span.Length;
#else
Expand All @@ -265,7 +316,17 @@ public bool TryCopyTo(RefEnumerable<T> destination)
/// </exception>
public void CopyTo(Span<T> destination)
{
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
if (this.step == 1)
{
MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in this.reference), this.length).CopyTo(destination);

return;
}

ref T sourceRef = ref Unsafe.AsRef(in this.reference);
int length = this.length;
#elif NETSTANDARD2_1_OR_GREATER
if (this.step == 1)
{
this.span.CopyTo(destination);
Expand Down Expand Up @@ -296,7 +357,9 @@ public void CopyTo(Span<T> destination)
/// <returns>Whether or not the operation was successful.</returns>
public bool TryCopyTo(Span<T> destination)
{
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
int length = this.length;
#elif NETSTANDARD2_1_OR_GREATER
int length = this.span.Length;
#else
int length = this.length;
Expand All @@ -315,7 +378,9 @@ public bool TryCopyTo(Span<T> destination)
/// <inheritdoc cref="RefEnumerable{T}.ToArray"/>
public T[] ToArray()
{
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
int length = this.length;
#elif NETSTANDARD2_1_OR_GREATER
int length = this.span.Length;
#else
int length = this.length;
Expand All @@ -341,7 +406,9 @@ public T[] ToArray()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ReadOnlyRefEnumerable<T>(RefEnumerable<T> enumerable)
{
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
return new(in enumerable.Reference, enumerable.Length, enumerable.Step);
#elif NETSTANDARD2_1_OR_GREATER
return new(enumerable.Span, enumerable.Step);
#else
return new(enumerable.Instance, enumerable.Offset, enumerable.Length, enumerable.Step);
Expand All @@ -353,7 +420,13 @@ public static implicit operator ReadOnlyRefEnumerable<T>(RefEnumerable<T> enumer
/// </summary>
public ref struct Enumerator
{
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
/// <inheritdoc cref="ReadOnlyRefEnumerable{T}.reference"/>
private readonly ref readonly T reference;

/// <inheritdoc cref="ReadOnlyRefEnumerable{T}.length"/>
private readonly int length;
#elif NETSTANDARD2_1_OR_GREATER
/// <inheritdoc cref="ReadOnlyRefEnumerable{T}.span"/>
private readonly ReadOnlySpan<T> span;
#else
Expand All @@ -375,7 +448,22 @@ public ref struct Enumerator
/// </summary>
private int position;

#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="Enumerator"/> struct.
/// </summary>
/// <param name="reference">The <typeparamref name="T"/> reference to the first item of the sequence.</param>
/// <param name="length">The length of the sequence.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Enumerator(in T reference, int length, int step)
{
this.reference = ref reference;
this.length = length;
this.step = step;
this.position = -1;
}
#elif NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="Enumerator"/> struct.
/// </summary>
Expand Down Expand Up @@ -411,7 +499,9 @@ internal Enumerator(object? instance, IntPtr offset, int length, int step)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
return ++this.position < this.length;
#elif NETSTANDARD2_1_OR_GREATER
return ++this.position < this.span.Length;
#else
return ++this.position < this.length;
Expand All @@ -424,7 +514,9 @@ public readonly ref readonly T Current
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
ref T r0 = ref Unsafe.AsRef(in this.reference);
#elif NETSTANDARD2_1_OR_GREATER
ref T r0 = ref this.span.DangerousGetReference();
#else
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,22 @@ public readonly Item Current
[EditorBrowsable(EditorBrowsableState.Never)]
public readonly ref struct Item
{
#if NET7_0_OR_GREATER
/// <summary>
/// The <typeparamref name="T"/> reference for the <see cref="Item"/> instance.
/// </summary>
private readonly ref readonly T reference;

/// <summary>
/// The index of the current <see cref="Item"/> instance.
/// </summary>
private readonly int index;
#else
/// <summary>
/// The source <see cref="ReadOnlySpan{T}"/> instance.
/// </summary>
private readonly ReadOnlySpan<T> span;
#endif

#if NETSTANDARD2_1_OR_GREATER
/// <summary>
Expand All @@ -95,7 +107,12 @@ public readonly ref struct Item
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Item(ref T value, int index)
{
#if NET7_0_OR_GREATER
this.reference = ref value;
this.index = index;
#else
this.span = MemoryMarshal.CreateReadOnlySpan(ref value, index);
#endif
}
#else
/// <summary>
Expand Down Expand Up @@ -124,7 +141,9 @@ public ref readonly T Value
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
return ref this.reference;
#elif NETSTANDARD2_1_OR_GREATER
return ref MemoryMarshal.GetReference(this.span);
#else
ref T r0 = ref MemoryMarshal.GetReference(this.span);
Expand All @@ -143,7 +162,9 @@ public int Index
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
#if NETSTANDARD2_1_OR_GREATER
#if NET7_0_OR_GREATER
return this.index;
#elif NETSTANDARD2_1_OR_GREATER
return this.span.Length;
#else
return this.index;
Expand Down
Loading