| File: System\Linq\Reverse.cs | Web Access |
| Project: src\runtime\src\libraries\System.Linq\src\System.Linq.csproj (System.Linq) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics; namespace System.Linq { public static partial class Enumerable { /// <summary> /// Returns a sequence with the elements of <paramref name="source"/> in reverse order. /// </summary> /// <typeparam name="TSource">The type of the elements of <paramref name="source"/>.</typeparam> /// <param name="source">The sequence whose elements should be reversed.</param> /// <returns>A sequence that enumerates the elements of <paramref name="source"/> in reverse.</returns> public static IEnumerable<TSource> Reverse<TSource>(this IEnumerable<TSource> source) { if (source is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (IsEmptyArray(source)) { return []; } return new ReverseIterator<TSource>(source); } /// <summary> /// Returns a sequence with the elements of <paramref name="source"/> in reverse order. /// </summary> /// <typeparam name="TSource">The type of the elements of <paramref name="source"/>.</typeparam> /// <param name="source">The array whose elements should be reversed.</param> /// <returns>A sequence whose elements correspond to those of the input sequence in reverse order.</returns> public static IEnumerable<TSource> Reverse<TSource>(this TSource[] source) { if (source is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (source.Length == 0) { return []; } return new ReverseIterator<TSource>(source); } /// <summary> /// An iterator that yields the items of an <see cref="IEnumerable{TSource}"/> in reverse. /// </summary> /// <typeparam name="TSource">The type of the source enumerable.</typeparam> private sealed partial class ReverseIterator<TSource> : Iterator<TSource> { private readonly IEnumerable<TSource> _source; private TSource[]? _buffer; public ReverseIterator(IEnumerable<TSource> source) { Debug.Assert(source is not null); _source = source; } private protected override Iterator<TSource> Clone() => new ReverseIterator<TSource>(_source); public override bool MoveNext() { if (_state - 2 <= -2) { // Either someone called a method and cast us to IEnumerable without calling GetEnumerator, // or we were already disposed. In either case, iteration has ended, so return false. // A comparison is made against -2 instead of _state <= 0 because we want to handle cases where // the source is really large and adding the bias causes _state to overflow. Debug.Assert(_state == -1 || _state == 0); Dispose(); return false; } switch (_state) { case 1: // Iteration has just started. Capture the source into an array and set _state to 2 + the count. // Having an extra field for the count would be more readable, but we save it into _state with a // bias instead to minimize field size of the iterator. TSource[] buffer = _source.ToArray(); _buffer = buffer; _state = buffer.Length + 2; goto default; default: // At this stage, _state starts from 2 + the count. _state - 3 represents the current index into the // buffer. It is continuously decremented until it hits 2, which means that we've run out of items to // yield and should return false. int index = _state - 3; if (index != -1) { Debug.Assert(_buffer is not null); _current = _buffer[index]; --_state; return true; } break; } Dispose(); return false; } public override void Dispose() { _buffer = null; // Just in case this ends up being long-lived, allow the memory to be reclaimed. base.Dispose(); } } } }