// 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.
// https://github.com/CommunityToolkit/dotnet/blob/main/CommunityToolkit.HighPerformance/Enumerables/SpanEnumerable%7BT%7D.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace FisheryLib;
///
/// A that enumerates the items in a given instance.
///
/// The type of items to enumerate.
[EditorBrowsable(EditorBrowsableState.Never)]
public ref struct SpanEnumerable
{
///
/// The source instance.
///
private readonly Span _span;
///
/// The current index within .
///
private int _index;
///
/// Initializes a new instance of the struct.
///
/// The source instance.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public SpanEnumerable(Span span)
{
_span = span;
_index = -1;
}
///
/// Implements the duck-typed method.
///
/// An instance targeting the current value.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly SpanEnumerable GetEnumerator() => this;
///
/// Implements the duck-typed method.
///
/// whether a new element is available, otherwise
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext() => ++_index < _span.Length;
///
/// Gets the duck-typed property.
///
public readonly Item Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
// On .NET Standard 2.1 and .NET Core (or on any target that offers runtime
// support for the Span types), we can save 4 bytes by piggybacking the
// current index in the length of the wrapped span. We're going to use the
// first item as the target reference, and the length as a host for the
// current original offset. This is not possible on eg. .NET Standard 2.0,
// as we lack the API to create Span-s from arbitrary references.
=> new(ref Unsafe.Add(ref _span.DangerousGetPinnableReference(), (nint)(uint)_index), _index);
}
///
/// An item from a source instance.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public readonly ref struct Item
{
///
/// The source instance.
///
private readonly Span _span;
///
/// 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) => _span = MemoryMarshal.CreateSpan(ref value, index);
///
/// Gets the reference to the current value.
///
public ref T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref MemoryMarshal.GetReference(_span);
}
///
/// Gets the current index.
///
public int Index
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _span.Length;
}
}
}