// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace CommunityToolkit.HighPerformance.Enumerables;
///
/// A that enumerates the items in a given instance.
///
/// The type of items to enumerate.
[EditorBrowsable(EditorBrowsableState.Never)]
public ref struct ReadOnlySpanEnumerable
{
///
/// The source instance.
///
private readonly ReadOnlySpan span;
///
/// The current index within .
///
private int index;
///
/// Initializes a new instance of the struct.
///
/// The source instance.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpanEnumerable(ReadOnlySpan span)
{
this.span = span;
this.index = -1;
}
///
/// Implements the duck-typed method.
///
/// An instance targeting the current value.
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly ReadOnlySpanEnumerable GetEnumerator() => this;
///
/// Implements the duck-typed method.
///
/// whether a new element is available, otherwise
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
return ++this.index < this.span.Length;
}
///
/// Gets the duck-typed property.
///
public readonly Item Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref MemoryMarshal.GetReference(this.span);
ref T ri = ref Unsafe.Add(ref r0, (nint)(uint)this.index);
// See comment in SpanEnumerable about this
return new Item(ref ri, this.index);
#else
return new Item(this.span, this.index);
#endif
}
}
///
/// An item from a source instance.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public readonly ref struct Item
{
///
/// The source instance.
///
private readonly ReadOnlySpan span;
#if NETSTANDARD2_1_OR_GREATER
///
/// Initializes a new instance of the struct.
///
/// A reference to the target value.
/// The index of the target value.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Item(ref T value, int index)
{
this.span = MemoryMarshal.CreateReadOnlySpan(ref value, index);
}
#else
///
/// The current index within .
///
private readonly int index;
///
/// Initializes a new instance of the struct.
///
/// The source instance.
/// The current index within .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Item(ReadOnlySpan span, int index)
{
this.span = span;
this.index = index;
}
#endif
///
/// Gets the reference to the current value.
///
public ref readonly T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
#if NETSTANDARD2_1_OR_GREATER
return ref MemoryMarshal.GetReference(this.span);
#else
ref T r0 = ref MemoryMarshal.GetReference(this.span);
ref T ri = ref Unsafe.Add(ref r0, (nint)(uint)this.index);
return ref ri;
#endif
}
}
///
/// Gets the current index.
///
public int Index
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
#if NETSTANDARD2_1_OR_GREATER
return this.span.Length;
#else
return this.index;
#endif
}
}
}
}