// 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 } } } }