| File: System\Buffers\BuffersExtensions.cs | Web Access |
| Project: src\runtime\src\libraries\System.Memory\src\System.Memory.csproj (System.Memory) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; namespace System.Buffers { /// <summary> /// Extension methods for <see cref="ReadOnlySequence{T}"/> /// </summary> public static class BuffersExtensions { /// <summary> /// Returns position of first occurrence of item in the <see cref="ReadOnlySequence{T}"/> /// </summary> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static SequencePosition? PositionOf<T>(in this ReadOnlySequence<T> source, T value) where T : IEquatable<T>? { if (source.IsSingleSegment) { int index = source.First.Span.IndexOf(value); if (index != -1) { return source.Seek(index); } return null; } else { return PositionOfMultiSegment(source, value); } } private static SequencePosition? PositionOfMultiSegment<T>(in ReadOnlySequence<T> source, T value) where T : IEquatable<T>? { SequencePosition position = source.Start; SequencePosition result = position; while (source.TryGet(ref position, out ReadOnlyMemory<T> memory)) { int index = memory.Span.IndexOf(value); if (index != -1) { return source.GetPosition(index, result); } else if (position.GetObject() == null) { break; } result = position; } return null; } /// <summary> /// Copy the <see cref="ReadOnlySequence{T}"/> to the specified <see cref="Span{Byte}"/>. /// </summary> /// <param name="source">The source <see cref="ReadOnlySequence{T}"/>.</param> /// <param name="destination">The destination <see cref="Span{Byte}"/>.</param> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void CopyTo<T>(in this ReadOnlySequence<T> source, Span<T> destination) { if (source.IsSingleSegment) { ReadOnlySpan<T> span = source.First.Span; if (span.Length > destination.Length) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.destination); span.CopyTo(destination); } else { CopyToMultiSegment(source, destination); } } private static void CopyToMultiSegment<T>(in ReadOnlySequence<T> sequence, Span<T> destination) { if (sequence.Length > destination.Length) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.destination); SequencePosition position = sequence.Start; while (sequence.TryGet(ref position, out ReadOnlyMemory<T> memory)) { ReadOnlySpan<T> span = memory.Span; span.CopyTo(destination); if (position.GetObject() != null) { destination = destination.Slice(span.Length); } else { break; } } } /// <summary> /// Converts the <see cref="ReadOnlySequence{T}"/> to an array /// </summary> public static T[] ToArray<T>(in this ReadOnlySequence<T> sequence) { var array = new T[sequence.Length]; sequence.CopyTo(array); return array; } /// <summary> /// Writes contents of <paramref name="value"/> to <paramref name="writer"/> /// </summary> /// <exception cref="System.ArgumentOutOfRangeException"> /// Thrown when the <paramref name="writer"/> is shorter than the <paramref name="value"/>. /// </exception> [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Write<T>(this IBufferWriter<T> writer, ReadOnlySpan<T> value) { Span<T> destination = writer.GetSpan(); // Fast path, try copying to the available memory directly if (value.Length <= destination.Length) { value.CopyTo(destination); writer.Advance(value.Length); } else { WriteMultiSegment(writer, value, destination); } } private static void WriteMultiSegment<T>(IBufferWriter<T> writer, in ReadOnlySpan<T> source, Span<T> destination) { ReadOnlySpan<T> input = source; while (true) { int writeSize = Math.Min(destination.Length, input.Length); input.Slice(0, writeSize).CopyTo(destination); writer.Advance(writeSize); input = input.Slice(writeSize); if (input.Length > 0) { destination = writer.GetSpan(); if (destination.IsEmpty) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.writer); } continue; } return; } } } }