<Compile Include="$(MSBuildThisFileDirectory)System\Memory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MemoryDebugView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MemoryExtensions.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\MemoryExtensions.Fast.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\MemoryExtensions.Globalization.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MemoryExtensions.Trim.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MethodAccessException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MidpointRounding.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Range.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\RankException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\ReadOnlySpan.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\ReadOnlySpan.Fast.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\ReadOnlyMemory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\AmbiguousMatchException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Assembly.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MarshalAsAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MarshalDirectiveException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MemoryMarshal.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MemoryMarshal.Fast.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\NativeCallableAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\NativeLibrary.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\OptionalAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SerializableAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Single.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Span.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Span.Fast.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SpanDebugView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.BinarySearch.cs" />
-// Licensed to the .NET Foundation under one or more agreements.
+// 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.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
-using Internal.Runtime.CompilerServices;
+using System.Text;
namespace System
{
- /// <summary>
- /// Extension methods for Span{T}, Memory{T}, and friends.
- /// </summary>
public static partial class MemoryExtensions
{
/// <summary>
+ /// Indicates whether the specified span contains only white-space characters.
+ /// </summary>
+ public static bool IsWhiteSpace(this ReadOnlySpan<char> span)
+ {
+ for (int i = 0; i < span.Length; i++)
+ {
+ if (!char.IsWhiteSpace(span[i]))
+ return false;
+ }
+ return true;
+ }
+
+ /// <summary>
/// Returns a value indicating whether the specified <paramref name="value"/> occurs within the <paramref name="span"/>.
/// <param name="span">The source span.</param>
/// <param name="value">The value to seek within the source span.</param>
}
/// <summary>
- /// Creates a new span over the portion of the target array.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<T> AsSpan<T>(this T[]? array, int start)
- {
- if (array == null)
- {
- if (start != 0)
- ThrowHelper.ThrowArgumentOutOfRangeException();
- return default;
- }
- if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
- ThrowHelper.ThrowArrayTypeMismatchException();
- if ((uint)start > (uint)array.Length)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- return new Span<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start), array.Length - start);
- }
-
- /// <summary>
- /// Creates a new span over the portion of the target array.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<T> AsSpan<T>(this T[]? array, Index startIndex)
- {
- if (array == null)
- {
- if (!startIndex.Equals(Index.Start))
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
-
- return default;
- }
-
- if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
- ThrowHelper.ThrowArrayTypeMismatchException();
-
- int actualIndex = startIndex.GetOffset(array.Length);
- if ((uint)actualIndex > (uint)array.Length)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- return new Span<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), actualIndex), array.Length - actualIndex);
- }
-
- /// <summary>
- /// Creates a new span over the portion of the target array.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<T> AsSpan<T>(this T[]? array, Range range)
- {
- if (array == null)
- {
- Index startIndex = range.Start;
- Index endIndex = range.End;
-
- if (!startIndex.Equals(Index.Start) || !endIndex.Equals(Index.Start))
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
-
- return default;
- }
-
- if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
- ThrowHelper.ThrowArrayTypeMismatchException();
-
- (int start, int length) = range.GetOffsetAndLength(array.Length);
- return new Span<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start), length);
- }
-
- /// <summary>
- /// Creates a new readonly span over the portion of the target string.
- /// </summary>
- /// <param name="text">The target string.</param>
- /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<char> AsSpan(this string? text)
- {
- if (text == null)
- return default;
-
- return new ReadOnlySpan<char>(ref text.GetRawStringData(), text.Length);
- }
-
- /// <summary>
- /// Creates a new readonly span over the portion of the target string.
+ /// Returns an enumeration of <see cref="Rune"/> from the provided span.
/// </summary>
- /// <param name="text">The target string.</param>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is null.</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index is not in range (<0 or >text.Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<char> AsSpan(this string? text, int start)
+ /// <remarks>
+ /// Invalid sequences will be represented in the enumeration by <see cref="Rune.ReplacementChar"/>.
+ /// </remarks>
+ public static SpanRuneEnumerator EnumerateRunes(this ReadOnlySpan<char> span)
{
- if (text == null)
- {
- if (start != 0)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
- return default;
- }
-
- if ((uint)start > (uint)text.Length)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
-
- return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), start), text.Length - start);
+ return new SpanRuneEnumerator(span);
}
/// <summary>
- /// Creates a new readonly span over the portion of the target string.
+ /// Returns an enumeration of <see cref="Rune"/> from the provided span.
/// </summary>
- /// <param name="text">The target string.</param>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <param name="length">The desired length for the slice (exclusive).</param>
- /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<char> AsSpan(this string? text, int start, int length)
- {
- if (text == null)
- {
- if (start != 0 || length != 0)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
- return default;
- }
-
-#if BIT64
- // See comment in Span<T>.Slice for how this works.
- if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)text.Length)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
-#else
- if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
-#endif
-
- return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), start), length);
- }
-
- /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
- /// <param name="text">The target string.</param>
- /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
- public static ReadOnlyMemory<char> AsMemory(this string? text)
- {
- if (text == null)
- return default;
-
- return new ReadOnlyMemory<char>(text, 0, text.Length);
- }
-
- /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
- /// <param name="text">The target string.</param>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index is not in range (<0 or >text.Length).
- /// </exception>
- public static ReadOnlyMemory<char> AsMemory(this string? text, int start)
- {
- if (text == null)
- {
- if (start != 0)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
- return default;
- }
-
- if ((uint)start > (uint)text.Length)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
-
- return new ReadOnlyMemory<char>(text, start, text.Length - start);
- }
-
- /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
- /// <param name="text">The target string.</param>
- /// <param name="startIndex">The index at which to begin this slice.</param>
- public static ReadOnlyMemory<char> AsMemory(this string? text, Index startIndex)
- {
- if (text == null)
- {
- if (!startIndex.Equals(Index.Start))
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-
- return default;
- }
-
- int actualIndex = startIndex.GetOffset(text.Length);
- if ((uint)actualIndex > (uint)text.Length)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- return new ReadOnlyMemory<char>(text, actualIndex, text.Length - actualIndex);
- }
-
- /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
- /// <param name="text">The target string.</param>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <param name="length">The desired length for the slice (exclusive).</param>
- /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
- /// </exception>
- public static ReadOnlyMemory<char> AsMemory(this string? text, int start, int length)
+ /// <remarks>
+ /// Invalid sequences will be represented in the enumeration by <see cref="Rune.ReplacementChar"/>.
+ /// </remarks>
+ public static SpanRuneEnumerator EnumerateRunes(this Span<char> span)
{
- if (text == null)
- {
- if (start != 0 || length != 0)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
- return default;
- }
-
-#if BIT64
- // See comment in Span<T>.Slice for how this works.
- if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)text.Length)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
-#else
- if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
-#endif
-
- return new ReadOnlyMemory<char>(text, start, length);
- }
-
- /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
- /// <param name="text">The target string.</param>
- /// <param name="range">The range used to indicate the start and length of the sliced string.</param>
- public static ReadOnlyMemory<char> AsMemory(this string? text, Range range)
- {
- if (text == null)
- {
- Index startIndex = range.Start;
- Index endIndex = range.End;
-
- if (!startIndex.Equals(Index.Start) || !endIndex.Equals(Index.Start))
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-
- return default;
- }
-
- (int start, int length) = range.GetOffsetAndLength(text.Length);
- return new ReadOnlyMemory<char>(text, start, length);
+ return new SpanRuneEnumerator(span);
}
}
}
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using System.Text;
using Internal.Runtime.CompilerServices;
public static partial class MemoryExtensions
{
/// <summary>
- /// Indicates whether the specified span contains only white-space characters.
+ /// Creates a new span over the portion of the target array.
/// </summary>
- public static bool IsWhiteSpace(this ReadOnlySpan<char> span)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span<T> AsSpan<T>(this T[]? array, int start)
{
- for (int i = 0; i < span.Length; i++)
+ if (array == null)
{
- if (!char.IsWhiteSpace(span[i]))
- return false;
+ if (start != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+ return default;
+ }
+ if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
+ ThrowHelper.ThrowArrayTypeMismatchException();
+ if ((uint)start > (uint)array.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new Span<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start), array.Length - start);
+ }
+
+ /// <summary>
+ /// Creates a new span over the portion of the target array.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span<T> AsSpan<T>(this T[]? array, Index startIndex)
+ {
+ if (array == null)
+ {
+ if (!startIndex.Equals(Index.Start))
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+
+ return default;
+ }
+
+ if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
+ ThrowHelper.ThrowArrayTypeMismatchException();
+
+ int actualIndex = startIndex.GetOffset(array.Length);
+ if ((uint)actualIndex > (uint)array.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new Span<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), actualIndex), array.Length - actualIndex);
+ }
+
+ /// <summary>
+ /// Creates a new span over the portion of the target array.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span<T> AsSpan<T>(this T[]? array, Range range)
+ {
+ if (array == null)
+ {
+ Index startIndex = range.Start;
+ Index endIndex = range.End;
+
+ if (!startIndex.Equals(Index.Start) || !endIndex.Equals(Index.Start))
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+
+ return default;
+ }
+
+ if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
+ ThrowHelper.ThrowArrayTypeMismatchException();
+
+ (int start, int length) = range.GetOffsetAndLength(array.Length);
+ return new Span<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start), length);
+ }
+
+ /// <summary>
+ /// Creates a new readonly span over the portion of the target string.
+ /// </summary>
+ /// <param name="text">The target string.</param>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<char> AsSpan(this string? text)
+ {
+ if (text == null)
+ return default;
+
+ return new ReadOnlySpan<char>(ref text.GetRawStringData(), text.Length);
+ }
+
+ /// <summary>
+ /// Creates a new readonly span over the portion of the target string.
+ /// </summary>
+ /// <param name="text">The target string.</param>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is null.</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index is not in range (<0 or >text.Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<char> AsSpan(this string? text, int start)
+ {
+ if (text == null)
+ {
+ if (start != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ return default;
+ }
+
+ if ((uint)start > (uint)text.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), start), text.Length - start);
+ }
+
+ /// <summary>
+ /// Creates a new readonly span over the portion of the target string.
+ /// </summary>
+ /// <param name="text">The target string.</param>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="length">The desired length for the slice (exclusive).</param>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<char> AsSpan(this string? text, int start, int length)
+ {
+ if (text == null)
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ return default;
+ }
+
+#if BIT64
+ // See comment in Span<T>.Slice for how this works.
+ if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)text.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+#else
+ if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+#endif
+
+ return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), start), length);
+ }
+
+ /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
+ /// <param name="text">The target string.</param>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
+ public static ReadOnlyMemory<char> AsMemory(this string? text)
+ {
+ if (text == null)
+ return default;
+
+ return new ReadOnlyMemory<char>(text, 0, text.Length);
+ }
+
+ /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
+ /// <param name="text">The target string.</param>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index is not in range (<0 or >text.Length).
+ /// </exception>
+ public static ReadOnlyMemory<char> AsMemory(this string? text, int start)
+ {
+ if (text == null)
+ {
+ if (start != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ return default;
+ }
+
+ if ((uint)start > (uint)text.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ return new ReadOnlyMemory<char>(text, start, text.Length - start);
+ }
+
+ /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
+ /// <param name="text">The target string.</param>
+ /// <param name="startIndex">The index at which to begin this slice.</param>
+ public static ReadOnlyMemory<char> AsMemory(this string? text, Index startIndex)
+ {
+ if (text == null)
+ {
+ if (!startIndex.Equals(Index.Start))
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
+
+ return default;
}
- return true;
+
+ int actualIndex = startIndex.GetOffset(text.Length);
+ if ((uint)actualIndex > (uint)text.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new ReadOnlyMemory<char>(text, actualIndex, text.Length - actualIndex);
+ }
+
+ /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
+ /// <param name="text">The target string.</param>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="length">The desired length for the slice (exclusive).</param>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
+ /// </exception>
+ public static ReadOnlyMemory<char> AsMemory(this string? text, int start, int length)
+ {
+ if (text == null)
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ return default;
+ }
+
+#if BIT64
+ // See comment in Span<T>.Slice for how this works.
+ if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)text.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+#else
+ if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+#endif
+
+ return new ReadOnlyMemory<char>(text, start, length);
+ }
+
+ /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
+ /// <param name="text">The target string.</param>
+ /// <param name="range">The range used to indicate the start and length of the sliced string.</param>
+ public static ReadOnlyMemory<char> AsMemory(this string? text, Range range)
+ {
+ if (text == null)
+ {
+ Index startIndex = range.Start;
+ Index endIndex = range.End;
+
+ if (!startIndex.Equals(Index.Start) || !endIndex.Equals(Index.Start))
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
+
+ return default;
+ }
+
+ (int start, int length) = range.GetOffsetAndLength(text.Length);
+ return new ReadOnlyMemory<char>(text, start, length);
}
/// <summary>
}
/// <summary>
- /// Returns an enumeration of <see cref="Rune"/> from the provided span.
- /// </summary>
- /// <remarks>
- /// Invalid sequences will be represented in the enumeration by <see cref="Rune.ReplacementChar"/>.
- /// </remarks>
- public static SpanRuneEnumerator EnumerateRunes(this ReadOnlySpan<char> span)
- {
- return new SpanRuneEnumerator(span);
- }
-
- /// <summary>
- /// Returns an enumeration of <see cref="Rune"/> from the provided span.
- /// </summary>
- /// <remarks>
- /// Invalid sequences will be represented in the enumeration by <see cref="Rune.ReplacementChar"/>.
- /// </remarks>
- public static SpanRuneEnumerator EnumerateRunes(this Span<char> span)
- {
- return new SpanRuneEnumerator(span);
- }
-
- /// <summary>
/// Reverses the sequence of the elements in the entire span.
/// </summary>
public static void Reverse<T>(this Span<T> span)
+++ /dev/null
-// 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.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Runtime.Versioning;
-using System.Text;
-using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
-using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
-using Internal.Runtime.CompilerServices;
-
-#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
-
-#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
-#if BIT64
-using nuint = System.UInt64;
-#else
-using nuint = System.UInt32;
-#endif
-
-namespace System
-{
- /// <summary>
- /// ReadOnlySpan represents a contiguous region of arbitrary memory. Unlike arrays, it can point to either managed
- /// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
- /// </summary>
- [NonVersionable]
- public readonly ref partial struct ReadOnlySpan<T>
- {
- /// <summary>A byref or a native ptr.</summary>
- internal readonly ByReference<T> _pointer;
- /// <summary>The number of elements this ReadOnlySpan contains.</summary>
- private readonly int _length;
-
- /// <summary>
- /// Creates a new read-only span over the entirety of the target array.
- /// </summary>
- /// <param name="array">The target array.</param>
- /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ReadOnlySpan(T[]? array)
- {
- if (array == null)
- {
- this = default;
- return; // returns default
- }
-
- _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()));
- _length = array.Length;
- }
-
- /// <summary>
- /// Creates a new read-only span over the portion of the target array beginning
- /// at 'start' index and ending at 'end' index (exclusive).
- /// </summary>
- /// <param name="array">The target array.</param>
- /// <param name="start">The index at which to begin the read-only span.</param>
- /// <param name="length">The number of items in the read-only span.</param>
- /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in the range (<0 or >Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ReadOnlySpan(T[]? array, int start, int length)
- {
- if (array == null)
- {
- if (start != 0 || length != 0)
- ThrowHelper.ThrowArgumentOutOfRangeException();
- this = default;
- return; // returns default
- }
-#if BIT64
- // See comment in Span<T>.Slice for how this works.
- if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)array.Length)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-#else
- if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
- ThrowHelper.ThrowArgumentOutOfRangeException();
-#endif
-
- _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
- _length = length;
- }
-
- /// <summary>
- /// Creates a new read-only span over the target unmanaged buffer. Clearly this
- /// is quite dangerous, because we are creating arbitrarily typed T's
- /// out of a void*-typed block of memory. And the length is not checked.
- /// But if this creation is correct, then all subsequent uses are correct.
- /// </summary>
- /// <param name="pointer">An unmanaged pointer to memory.</param>
- /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="T"/> is reference type or contains pointers and hence cannot be stored in unmanaged memory.
- /// </exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="length"/> is negative.
- /// </exception>
- [CLSCompliant(false)]
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe ReadOnlySpan(void* pointer, int length)
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
- if (length < 0)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
- _length = length;
- }
-
- // Constructor for internal use only.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal ReadOnlySpan(ref T ptr, int length)
- {
- Debug.Assert(length >= 0);
-
- _pointer = new ByReference<T>(ref ptr);
- _length = length;
- }
-
- /// <summary>
- /// Returns the specified element of the read-only span.
- /// </summary>
- /// <param name="index"></param>
- /// <returns></returns>
- /// <exception cref="System.IndexOutOfRangeException">
- /// Thrown when index less than 0 or index greater than or equal to Length
- /// </exception>
- public ref readonly T this[int index]
- {
- [Intrinsic]
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [NonVersionable]
- get
- {
- if ((uint)index >= (uint)_length)
- ThrowHelper.ThrowIndexOutOfRangeException();
- return ref Unsafe.Add(ref _pointer.Value, index);
- }
- }
-
- /// <summary>
- /// Returns a reference to the 0th element of the Span. If the Span is empty, returns null reference.
- /// It can be used for pinning and is required to support the use of span within a fixed statement.
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public ref readonly T GetPinnableReference()
- {
- // Ensure that the native code has just one forward branch that is predicted-not-taken.
- ref T ret = ref Unsafe.NullRef<T>();
- if (_length != 0) ret = ref _pointer.Value;
- return ref ret;
- }
-
- /// <summary>
- /// Copies the contents of this read-only span into destination span. If the source
- /// and destinations overlap, this method behaves as if the original values in
- /// a temporary location before the destination is overwritten.
- ///
- /// <param name="destination">The span to copy items into.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when the destination Span is shorter than the source Span.
- /// </exception>
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void CopyTo(Span<T> destination)
- {
- // Using "if (!TryCopyTo(...))" results in two branches: one for the length
- // check, and one for the result of TryCopyTo. Since these checks are equivalent,
- // we can optimize by performing the check once ourselves then calling Memmove directly.
-
- if ((uint)_length <= (uint)destination.Length)
- {
- Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length);
- }
- else
- {
- ThrowHelper.ThrowArgumentException_DestinationTooShort();
- }
- }
-
- /// <summary>
- /// Copies the contents of this read-only span into destination span. If the source
- /// and destinations overlap, this method behaves as if the original values in
- /// a temporary location before the destination is overwritten.
- /// </summary>
- /// <returns>If the destination span is shorter than the source span, this method
- /// return false and no data is written to the destination.</returns>
- /// <param name="destination">The span to copy items into.</param>
- public bool TryCopyTo(Span<T> destination)
- {
- bool retVal = false;
- if ((uint)_length <= (uint)destination.Length)
- {
- Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length);
- retVal = true;
- }
- return retVal;
- }
-
- /// <summary>
- /// Returns true if left and right point at the same memory and have the same length. Note that
- /// this does *not* check to see if the *contents* are equal.
- /// </summary>
- public static bool operator ==(ReadOnlySpan<T> left, ReadOnlySpan<T> right) =>
- left._length == right._length &&
- Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
-
- /// <summary>
- /// For <see cref="ReadOnlySpan{Char}"/>, returns a new instance of string that represents the characters pointed to by the span.
- /// Otherwise, returns a <see cref="string"/> with the name of the type and the number of elements.
- /// </summary>
- public override string ToString()
- {
- if (typeof(T) == typeof(char))
- {
- return new string(new ReadOnlySpan<char>(ref Unsafe.As<T, char>(ref _pointer.Value), _length));
- }
-#if FEATURE_UTF8STRING
- else if (typeof(T) == typeof(Char8))
- {
- // TODO_UTF8STRING: Call into optimized transcoding routine when it's available.
- return Encoding.UTF8.GetString(new ReadOnlySpan<byte>(ref Unsafe.As<T, byte>(ref _pointer.Value), _length));
- }
-#endif // FEATURE_UTF8STRING
- return string.Format("System.ReadOnlySpan<{0}>[{1}]", typeof(T).Name, _length);
- }
-
- /// <summary>
- /// Forms a slice out of the given read-only span, beginning at 'start'.
- /// </summary>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index is not in range (<0 or >Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ReadOnlySpan<T> Slice(int start)
- {
- if ((uint)start > (uint)_length)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, start), _length - start);
- }
-
- /// <summary>
- /// Forms a slice out of the given read-only span, beginning at 'start', of given length
- /// </summary>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <param name="length">The desired length for the slice (exclusive).</param>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in range (<0 or >Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ReadOnlySpan<T> Slice(int start, int length)
- {
-#if BIT64
- // See comment in Span<T>.Slice for how this works.
- if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)_length)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-#else
- if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
- ThrowHelper.ThrowArgumentOutOfRangeException();
-#endif
-
- return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
- }
-
- /// <summary>
- /// Copies the contents of this read-only span into a new array. This heap
- /// allocates, so should generally be avoided, however it is sometimes
- /// necessary to bridge the gap with APIs written in terms of arrays.
- /// </summary>
- public T[] ToArray()
- {
- if (_length == 0)
- return Array.Empty<T>();
-
- var destination = new T[_length];
- Buffer.Memmove(ref Unsafe.As<byte, T>(ref destination.GetRawSzArrayData()), ref _pointer.Value, (nuint)_length);
- return destination;
- }
- }
-}
// 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.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
-
using System.Runtime.Versioning;
+using System.Text;
+using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
+using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
+using Internal.Runtime.CompilerServices;
#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
+#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif
+
namespace System
{
/// <summary>
/// </summary>
[DebuggerTypeProxy(typeof(SpanDebugView<>))]
[DebuggerDisplay("{ToString(),raw}")]
- public readonly ref partial struct ReadOnlySpan<T>
+ [NonVersionable]
+ public readonly ref struct ReadOnlySpan<T>
{
+ /// <summary>A byref or a native ptr.</summary>
+ internal readonly ByReference<T> _pointer;
+ /// <summary>The number of elements this ReadOnlySpan contains.</summary>
+ private readonly int _length;
+
+ /// <summary>
+ /// Creates a new read-only span over the entirety of the target array.
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan(T[]? array)
+ {
+ if (array == null)
+ {
+ this = default;
+ return; // returns default
+ }
+
+ _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()));
+ _length = array.Length;
+ }
+
+ /// <summary>
+ /// Creates a new read-only span over the portion of the target array beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <param name="start">The index at which to begin the read-only span.</param>
+ /// <param name="length">The number of items in the read-only span.</param>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (<0 or >Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan(T[]? array, int start, int length)
+ {
+ if (array == null)
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+ this = default;
+ return; // returns default
+ }
+#if BIT64
+ // See comment in Span<T>.Slice for how this works.
+ if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)array.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+#else
+ if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+#endif
+
+ _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
+ _length = length;
+ }
+
+ /// <summary>
+ /// Creates a new read-only span over the target unmanaged buffer. Clearly this
+ /// is quite dangerous, because we are creating arbitrarily typed T's
+ /// out of a void*-typed block of memory. And the length is not checked.
+ /// But if this creation is correct, then all subsequent uses are correct.
+ /// </summary>
+ /// <param name="pointer">An unmanaged pointer to memory.</param>
+ /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> is reference type or contains pointers and hence cannot be stored in unmanaged memory.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="length"/> is negative.
+ /// </exception>
+ [CLSCompliant(false)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe ReadOnlySpan(void* pointer, int length)
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+ if (length < 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
+ _length = length;
+ }
+
+ // Constructor for internal use only.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal ReadOnlySpan(ref T ptr, int length)
+ {
+ Debug.Assert(length >= 0);
+
+ _pointer = new ByReference<T>(ref ptr);
+ _length = length;
+ }
+
+ /// <summary>
+ /// Returns the specified element of the read-only span.
+ /// </summary>
+ /// <param name="index"></param>
+ /// <returns></returns>
+ /// <exception cref="System.IndexOutOfRangeException">
+ /// Thrown when index less than 0 or index greater than or equal to Length
+ /// </exception>
+ public ref readonly T this[int index]
+ {
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [NonVersionable]
+ get
+ {
+ if ((uint)index >= (uint)_length)
+ ThrowHelper.ThrowIndexOutOfRangeException();
+ return ref Unsafe.Add(ref _pointer.Value, index);
+ }
+ }
+
/// <summary>
/// The number of items in the read-only span.
/// </summary>
get => ref _span[_index];
}
}
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the Span. If the Span is empty, returns null reference.
+ /// It can be used for pinning and is required to support the use of span within a fixed statement.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ref readonly T GetPinnableReference()
+ {
+ // Ensure that the native code has just one forward branch that is predicted-not-taken.
+ ref T ret = ref Unsafe.NullRef<T>();
+ if (_length != 0) ret = ref _pointer.Value;
+ return ref ret;
+ }
+
+ /// <summary>
+ /// Copies the contents of this read-only span into destination span. If the source
+ /// and destinations overlap, this method behaves as if the original values in
+ /// a temporary location before the destination is overwritten.
+ ///
+ /// <param name="destination">The span to copy items into.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when the destination Span is shorter than the source Span.
+ /// </exception>
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void CopyTo(Span<T> destination)
+ {
+ // Using "if (!TryCopyTo(...))" results in two branches: one for the length
+ // check, and one for the result of TryCopyTo. Since these checks are equivalent,
+ // we can optimize by performing the check once ourselves then calling Memmove directly.
+
+ if ((uint)_length <= (uint)destination.Length)
+ {
+ Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length);
+ }
+ else
+ {
+ ThrowHelper.ThrowArgumentException_DestinationTooShort();
+ }
+ }
+
+ /// <summary>
+ /// Copies the contents of this read-only span into destination span. If the source
+ /// and destinations overlap, this method behaves as if the original values in
+ /// a temporary location before the destination is overwritten.
+ /// </summary>
+ /// <returns>If the destination span is shorter than the source span, this method
+ /// return false and no data is written to the destination.</returns>
+ /// <param name="destination">The span to copy items into.</param>
+ public bool TryCopyTo(Span<T> destination)
+ {
+ bool retVal = false;
+ if ((uint)_length <= (uint)destination.Length)
+ {
+ Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length);
+ retVal = true;
+ }
+ return retVal;
+ }
+
+ /// <summary>
+ /// Returns true if left and right point at the same memory and have the same length. Note that
+ /// this does *not* check to see if the *contents* are equal.
+ /// </summary>
+ public static bool operator ==(ReadOnlySpan<T> left, ReadOnlySpan<T> right) =>
+ left._length == right._length &&
+ Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
+
+ /// <summary>
+ /// For <see cref="ReadOnlySpan{Char}"/>, returns a new instance of string that represents the characters pointed to by the span.
+ /// Otherwise, returns a <see cref="string"/> with the name of the type and the number of elements.
+ /// </summary>
+ public override string ToString()
+ {
+ if (typeof(T) == typeof(char))
+ {
+ return new string(new ReadOnlySpan<char>(ref Unsafe.As<T, char>(ref _pointer.Value), _length));
+ }
+#if FEATURE_UTF8STRING
+ else if (typeof(T) == typeof(Char8))
+ {
+ // TODO_UTF8STRING: Call into optimized transcoding routine when it's available.
+ return Encoding.UTF8.GetString(new ReadOnlySpan<byte>(ref Unsafe.As<T, byte>(ref _pointer.Value), _length));
+ }
+#endif // FEATURE_UTF8STRING
+ return string.Format("System.ReadOnlySpan<{0}>[{1}]", typeof(T).Name, _length);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given read-only span, beginning at 'start'.
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index is not in range (<0 or >Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan<T> Slice(int start)
+ {
+ if ((uint)start > (uint)_length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, start), _length - start);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given read-only span, beginning at 'start', of given length
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="length">The desired length for the slice (exclusive).</param>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in range (<0 or >Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan<T> Slice(int start, int length)
+ {
+#if BIT64
+ // See comment in Span<T>.Slice for how this works.
+ if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)_length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+#else
+ if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+#endif
+
+ return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
+ }
+
+ /// <summary>
+ /// Copies the contents of this read-only span into a new array. This heap
+ /// allocates, so should generally be avoided, however it is sometimes
+ /// necessary to bridge the gap with APIs written in terms of arrays.
+ /// </summary>
+ public T[] ToArray()
+ {
+ if (_length == 0)
+ return Array.Empty<T>();
+
+ var destination = new T[_length];
+ Buffer.Memmove(ref Unsafe.As<byte, T>(ref destination.GetRawSzArrayData()), ref _pointer.Value, (nuint)_length);
+ return destination;
+ }
}
}
+++ /dev/null
-// 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.Runtime.CompilerServices;
-using Internal.Runtime.CompilerServices;
-
-namespace System.Runtime.InteropServices
-{
- /// <summary>
- /// Provides a collection of methods for interoperating with <see cref="Memory{T}"/>, <see cref="ReadOnlyMemory{T}"/>,
- /// <see cref="Span{T}"/>, and <see cref="ReadOnlySpan{T}"/>.
- /// </summary>
- public static partial class MemoryMarshal
- {
- /// <summary>
- /// Casts a Span of one primitive type <typeparamref name="T"/> to Span of bytes.
- /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <param name="span">The source slice, of type <typeparamref name="T"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="T"/> contains pointers.
- /// </exception>
- /// <exception cref="System.OverflowException">
- /// Thrown if the Length property of the new Span would exceed int.MaxValue.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<byte> AsBytes<T>(Span<T> span)
- where T : struct
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
-
- return new Span<byte>(
- ref Unsafe.As<T, byte>(ref GetReference(span)),
- checked(span.Length * Unsafe.SizeOf<T>()));
- }
-
- /// <summary>
- /// Casts a ReadOnlySpan of one primitive type <typeparamref name="T"/> to ReadOnlySpan of bytes.
- /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <param name="span">The source slice, of type <typeparamref name="T"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="T"/> contains pointers.
- /// </exception>
- /// <exception cref="System.OverflowException">
- /// Thrown if the Length property of the new Span would exceed int.MaxValue.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<byte> AsBytes<T>(ReadOnlySpan<T> span)
- where T : struct
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
-
- return new ReadOnlySpan<byte>(
- ref Unsafe.As<T, byte>(ref GetReference(span)),
- checked(span.Length * Unsafe.SizeOf<T>()));
- }
-
- /// <summary>Creates a <see cref="Memory{T}"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
- /// <param name="memory">The <see cref="ReadOnlyMemory{T}"/>.</param>
- /// <returns>A <see cref="Memory{T}"/> representing the same memory as the <see cref="ReadOnlyMemory{T}"/>, but writable.</returns>
- /// <remarks>
- /// <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> must be used with extreme caution. <see cref="ReadOnlyMemory{T}"/> is used
- /// to represent immutable data and other memory that is not meant to be written to; <see cref="Memory{T}"/> instances created
- /// by <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> should not be written to. The method exists to enable variables typed
- /// as <see cref="Memory{T}"/> but only used for reading to store a <see cref="ReadOnlyMemory{T}"/>.
- /// </remarks>
- public static Memory<T> AsMemory<T>(ReadOnlyMemory<T> memory) =>
- Unsafe.As<ReadOnlyMemory<T>, Memory<T>>(ref memory);
-
- /// <summary>
- /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced.
- /// </summary>
- public static ref T GetReference<T>(Span<T> span) => ref span._pointer.Value;
-
- /// <summary>
- /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced.
- /// </summary>
- public static ref T GetReference<T>(ReadOnlySpan<T> span) => ref span._pointer.Value;
-
- /// <summary>
- /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to fake non-null pointer. Such a reference can be used
- /// for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static unsafe ref T GetNonNullPinnableReference<T>(Span<T> span) => ref (span.Length != 0) ? ref span._pointer.Value : ref Unsafe.AsRef<T>((void*)1);
-
- /// <summary>
- /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to fake non-null pointer. Such a reference
- /// can be used for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static unsafe ref T GetNonNullPinnableReference<T>(ReadOnlySpan<T> span) => ref (span.Length != 0) ? ref span._pointer.Value : ref Unsafe.AsRef<T>((void*)1);
-
- /// <summary>
- /// Casts a Span of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
- /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <remarks>
- /// Supported only for platforms that support misaligned memory access or when the memory block is aligned by other means.
- /// </remarks>
- /// <param name="span">The source slice, of type <typeparamref name="TFrom"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<TTo> Cast<TFrom, TTo>(Span<TFrom> span)
- where TFrom : struct
- where TTo : struct
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
- if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
-
- // Use unsigned integers - unsigned division by constant (especially by power of 2)
- // and checked casts are faster and smaller.
- uint fromSize = (uint)Unsafe.SizeOf<TFrom>();
- uint toSize = (uint)Unsafe.SizeOf<TTo>();
- uint fromLength = (uint)span.Length;
- int toLength;
- if (fromSize == toSize)
- {
- // Special case for same size types - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
- // should be optimized to just `length` but the JIT doesn't do that today.
- toLength = (int)fromLength;
- }
- else if (fromSize == 1)
- {
- // Special case for byte sized TFrom - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
- // becomes `(ulong)fromLength / (ulong)toSize` but the JIT can't narrow it down to `int`
- // and can't eliminate the checked cast. This also avoids a 32 bit specific issue,
- // the JIT can't eliminate long multiply by 1.
- toLength = (int)(fromLength / toSize);
- }
- else
- {
- // Ensure that casts are done in such a way that the JIT is able to "see"
- // the uint->ulong casts and the multiply together so that on 32 bit targets
- // 32x32to64 multiplication is used.
- ulong toLengthUInt64 = (ulong)fromLength * (ulong)fromSize / (ulong)toSize;
- toLength = checked((int)toLengthUInt64);
- }
-
- return new Span<TTo>(
- ref Unsafe.As<TFrom, TTo>(ref span._pointer.Value),
- toLength);
- }
-
- /// <summary>
- /// Casts a ReadOnlySpan of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
- /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <remarks>
- /// Supported only for platforms that support misaligned memory access or when the memory block is aligned by other means.
- /// </remarks>
- /// <param name="span">The source slice, of type <typeparamref name="TFrom"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<TTo> Cast<TFrom, TTo>(ReadOnlySpan<TFrom> span)
- where TFrom : struct
- where TTo : struct
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
- if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
-
- // Use unsigned integers - unsigned division by constant (especially by power of 2)
- // and checked casts are faster and smaller.
- uint fromSize = (uint)Unsafe.SizeOf<TFrom>();
- uint toSize = (uint)Unsafe.SizeOf<TTo>();
- uint fromLength = (uint)span.Length;
- int toLength;
- if (fromSize == toSize)
- {
- // Special case for same size types - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
- // should be optimized to just `length` but the JIT doesn't do that today.
- toLength = (int)fromLength;
- }
- else if (fromSize == 1)
- {
- // Special case for byte sized TFrom - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
- // becomes `(ulong)fromLength / (ulong)toSize` but the JIT can't narrow it down to `int`
- // and can't eliminate the checked cast. This also avoids a 32 bit specific issue,
- // the JIT can't eliminate long multiply by 1.
- toLength = (int)(fromLength / toSize);
- }
- else
- {
- // Ensure that casts are done in such a way that the JIT is able to "see"
- // the uint->ulong casts and the multiply together so that on 32 bit targets
- // 32x32to64 multiplication is used.
- ulong toLengthUInt64 = (ulong)fromLength * (ulong)fromSize / (ulong)toSize;
- toLength = checked((int)toLengthUInt64);
- }
-
- return new ReadOnlySpan<TTo>(
- ref Unsafe.As<TFrom, TTo>(ref MemoryMarshal.GetReference(span)),
- toLength);
- }
-
- /// <summary>
- /// Create a new span over a portion of a regular managed object. This can be useful
- /// if part of a managed object represents a "fixed array." This is dangerous because the
- /// <paramref name="length"/> is not checked.
- /// </summary>
- /// <param name="reference">A reference to data.</param>
- /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
- /// <returns>The lifetime of the returned span will not be validated for safety by span-aware languages.</returns>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<T> CreateSpan<T>(ref T reference, int length) => new Span<T>(ref reference, length);
-
- /// <summary>
- /// Create a new read-only span over a portion of a regular managed object. This can be useful
- /// if part of a managed object represents a "fixed array." This is dangerous because the
- /// <paramref name="length"/> is not checked.
- /// </summary>
- /// <param name="reference">A reference to data.</param>
- /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
- /// <returns>The lifetime of the returned span will not be validated for safety by span-aware languages.</returns>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<T> CreateReadOnlySpan<T>(ref T reference, int length) => new ReadOnlySpan<T>(ref reference, length);
- }
-}
/// Provides a collection of methods for interoperating with <see cref="Memory{T}"/>, <see cref="ReadOnlyMemory{T}"/>,
/// <see cref="Span{T}"/>, and <see cref="ReadOnlySpan{T}"/>.
/// </summary>
- public static partial class MemoryMarshal
+ public static class MemoryMarshal
{
/// <summary>
+ /// Casts a Span of one primitive type <typeparamref name="T"/> to Span of bytes.
+ /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <param name="span">The source slice, of type <typeparamref name="T"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> contains pointers.
+ /// </exception>
+ /// <exception cref="System.OverflowException">
+ /// Thrown if the Length property of the new Span would exceed int.MaxValue.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span<byte> AsBytes<T>(Span<T> span)
+ where T : struct
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+
+ return new Span<byte>(
+ ref Unsafe.As<T, byte>(ref GetReference(span)),
+ checked(span.Length * Unsafe.SizeOf<T>()));
+ }
+
+ /// <summary>
+ /// Casts a ReadOnlySpan of one primitive type <typeparamref name="T"/> to ReadOnlySpan of bytes.
+ /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <param name="span">The source slice, of type <typeparamref name="T"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> contains pointers.
+ /// </exception>
+ /// <exception cref="System.OverflowException">
+ /// Thrown if the Length property of the new Span would exceed int.MaxValue.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<byte> AsBytes<T>(ReadOnlySpan<T> span)
+ where T : struct
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+
+ return new ReadOnlySpan<byte>(
+ ref Unsafe.As<T, byte>(ref GetReference(span)),
+ checked(span.Length * Unsafe.SizeOf<T>()));
+ }
+
+ /// <summary>Creates a <see cref="Memory{T}"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
+ /// <param name="memory">The <see cref="ReadOnlyMemory{T}"/>.</param>
+ /// <returns>A <see cref="Memory{T}"/> representing the same memory as the <see cref="ReadOnlyMemory{T}"/>, but writable.</returns>
+ /// <remarks>
+ /// <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> must be used with extreme caution. <see cref="ReadOnlyMemory{T}"/> is used
+ /// to represent immutable data and other memory that is not meant to be written to; <see cref="Memory{T}"/> instances created
+ /// by <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> should not be written to. The method exists to enable variables typed
+ /// as <see cref="Memory{T}"/> but only used for reading to store a <see cref="ReadOnlyMemory{T}"/>.
+ /// </remarks>
+ public static Memory<T> AsMemory<T>(ReadOnlyMemory<T> memory) =>
+ Unsafe.As<ReadOnlyMemory<T>, Memory<T>>(ref memory);
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
+ /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced.
+ /// </summary>
+ public static ref T GetReference<T>(Span<T> span) => ref span._pointer.Value;
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to the location where the 0th element
+ /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced.
+ /// </summary>
+ public static ref T GetReference<T>(ReadOnlySpan<T> span) => ref span._pointer.Value;
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to fake non-null pointer. Such a reference can be used
+ /// for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe ref T GetNonNullPinnableReference<T>(Span<T> span) => ref (span.Length != 0) ? ref span._pointer.Value : ref Unsafe.AsRef<T>((void*)1);
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to fake non-null pointer. Such a reference
+ /// can be used for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe ref T GetNonNullPinnableReference<T>(ReadOnlySpan<T> span) => ref (span.Length != 0) ? ref span._pointer.Value : ref Unsafe.AsRef<T>((void*)1);
+
+ /// <summary>
+ /// Casts a Span of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
+ /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <remarks>
+ /// Supported only for platforms that support misaligned memory access or when the memory block is aligned by other means.
+ /// </remarks>
+ /// <param name="span">The source slice, of type <typeparamref name="TFrom"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span<TTo> Cast<TFrom, TTo>(Span<TFrom> span)
+ where TFrom : struct
+ where TTo : struct
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
+
+ // Use unsigned integers - unsigned division by constant (especially by power of 2)
+ // and checked casts are faster and smaller.
+ uint fromSize = (uint)Unsafe.SizeOf<TFrom>();
+ uint toSize = (uint)Unsafe.SizeOf<TTo>();
+ uint fromLength = (uint)span.Length;
+ int toLength;
+ if (fromSize == toSize)
+ {
+ // Special case for same size types - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
+ // should be optimized to just `length` but the JIT doesn't do that today.
+ toLength = (int)fromLength;
+ }
+ else if (fromSize == 1)
+ {
+ // Special case for byte sized TFrom - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
+ // becomes `(ulong)fromLength / (ulong)toSize` but the JIT can't narrow it down to `int`
+ // and can't eliminate the checked cast. This also avoids a 32 bit specific issue,
+ // the JIT can't eliminate long multiply by 1.
+ toLength = (int)(fromLength / toSize);
+ }
+ else
+ {
+ // Ensure that casts are done in such a way that the JIT is able to "see"
+ // the uint->ulong casts and the multiply together so that on 32 bit targets
+ // 32x32to64 multiplication is used.
+ ulong toLengthUInt64 = (ulong)fromLength * (ulong)fromSize / (ulong)toSize;
+ toLength = checked((int)toLengthUInt64);
+ }
+
+ return new Span<TTo>(
+ ref Unsafe.As<TFrom, TTo>(ref span._pointer.Value),
+ toLength);
+ }
+
+ /// <summary>
+ /// Casts a ReadOnlySpan of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
+ /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <remarks>
+ /// Supported only for platforms that support misaligned memory access or when the memory block is aligned by other means.
+ /// </remarks>
+ /// <param name="span">The source slice, of type <typeparamref name="TFrom"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<TTo> Cast<TFrom, TTo>(ReadOnlySpan<TFrom> span)
+ where TFrom : struct
+ where TTo : struct
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
+
+ // Use unsigned integers - unsigned division by constant (especially by power of 2)
+ // and checked casts are faster and smaller.
+ uint fromSize = (uint)Unsafe.SizeOf<TFrom>();
+ uint toSize = (uint)Unsafe.SizeOf<TTo>();
+ uint fromLength = (uint)span.Length;
+ int toLength;
+ if (fromSize == toSize)
+ {
+ // Special case for same size types - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
+ // should be optimized to just `length` but the JIT doesn't do that today.
+ toLength = (int)fromLength;
+ }
+ else if (fromSize == 1)
+ {
+ // Special case for byte sized TFrom - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
+ // becomes `(ulong)fromLength / (ulong)toSize` but the JIT can't narrow it down to `int`
+ // and can't eliminate the checked cast. This also avoids a 32 bit specific issue,
+ // the JIT can't eliminate long multiply by 1.
+ toLength = (int)(fromLength / toSize);
+ }
+ else
+ {
+ // Ensure that casts are done in such a way that the JIT is able to "see"
+ // the uint->ulong casts and the multiply together so that on 32 bit targets
+ // 32x32to64 multiplication is used.
+ ulong toLengthUInt64 = (ulong)fromLength * (ulong)fromSize / (ulong)toSize;
+ toLength = checked((int)toLengthUInt64);
+ }
+
+ return new ReadOnlySpan<TTo>(
+ ref Unsafe.As<TFrom, TTo>(ref MemoryMarshal.GetReference(span)),
+ toLength);
+ }
+
+ /// <summary>
+ /// Create a new span over a portion of a regular managed object. This can be useful
+ /// if part of a managed object represents a "fixed array." This is dangerous because the
+ /// <paramref name="length"/> is not checked.
+ /// </summary>
+ /// <param name="reference">A reference to data.</param>
+ /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+ /// <returns>The lifetime of the returned span will not be validated for safety by span-aware languages.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span<T> CreateSpan<T>(ref T reference, int length) => new Span<T>(ref reference, length);
+
+ /// <summary>
+ /// Create a new read-only span over a portion of a regular managed object. This can be useful
+ /// if part of a managed object represents a "fixed array." This is dangerous because the
+ /// <paramref name="length"/> is not checked.
+ /// </summary>
+ /// <param name="reference">A reference to data.</param>
+ /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+ /// <returns>The lifetime of the returned span will not be validated for safety by span-aware languages.</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<T> CreateReadOnlySpan<T>(ref T reference, int length) => new ReadOnlySpan<T>(ref reference, length);
+
+ /// <summary>
/// Get an array segment from the underlying memory.
/// If unable to get the array segment, return false with a default array segment.
/// </summary>
+++ /dev/null
-// 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.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Runtime.Versioning;
-using System.Text;
-using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
-using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
-using Internal.Runtime.CompilerServices;
-
-#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
-
-#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
-#if BIT64
-using nuint = System.UInt64;
-#else
-using nuint = System.UInt32;
-#endif
-
-namespace System
-{
- /// <summary>
- /// Span represents a contiguous region of arbitrary memory. Unlike arrays, it can point to either managed
- /// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
- /// </summary>
- [NonVersionable]
- public readonly ref partial struct Span<T>
- {
- /// <summary>A byref or a native ptr.</summary>
- internal readonly ByReference<T> _pointer;
- /// <summary>The number of elements this Span contains.</summary>
- private readonly int _length;
-
- /// <summary>
- /// Creates a new span over the entirety of the target array.
- /// </summary>
- /// <param name="array">The target array.</param>
- /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
- /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Span(T[]? array)
- {
- if (array == null)
- {
- this = default;
- return; // returns default
- }
- if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
- ThrowHelper.ThrowArrayTypeMismatchException();
-
- _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()));
- _length = array.Length;
- }
-
- /// <summary>
- /// Creates a new span over the portion of the target array beginning
- /// at 'start' index and ending at 'end' index (exclusive).
- /// </summary>
- /// <param name="array">The target array.</param>
- /// <param name="start">The index at which to begin the span.</param>
- /// <param name="length">The number of items in the span.</param>
- /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
- /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in the range (<0 or >Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Span(T[]? array, int start, int length)
- {
- if (array == null)
- {
- if (start != 0 || length != 0)
- ThrowHelper.ThrowArgumentOutOfRangeException();
- this = default;
- return; // returns default
- }
- if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
- ThrowHelper.ThrowArrayTypeMismatchException();
-#if BIT64
- // See comment in Span<T>.Slice for how this works.
- if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)array.Length)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-#else
- if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
- ThrowHelper.ThrowArgumentOutOfRangeException();
-#endif
-
- _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
- _length = length;
- }
-
- /// <summary>
- /// Creates a new span over the target unmanaged buffer. Clearly this
- /// is quite dangerous, because we are creating arbitrarily typed T's
- /// out of a void*-typed block of memory. And the length is not checked.
- /// But if this creation is correct, then all subsequent uses are correct.
- /// </summary>
- /// <param name="pointer">An unmanaged pointer to memory.</param>
- /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="T"/> is reference type or contains pointers and hence cannot be stored in unmanaged memory.
- /// </exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="length"/> is negative.
- /// </exception>
- [CLSCompliant(false)]
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe Span(void* pointer, int length)
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
- if (length < 0)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
- _length = length;
- }
-
- // Constructor for internal use only.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal Span(ref T ptr, int length)
- {
- Debug.Assert(length >= 0);
-
- _pointer = new ByReference<T>(ref ptr);
- _length = length;
- }
-
- /// <summary>
- /// Returns a reference to specified element of the Span.
- /// </summary>
- /// <param name="index"></param>
- /// <returns></returns>
- /// <exception cref="System.IndexOutOfRangeException">
- /// Thrown when index less than 0 or index greater than or equal to Length
- /// </exception>
- public ref T this[int index]
- {
- [Intrinsic]
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [NonVersionable]
- get
- {
- if ((uint)index >= (uint)_length)
- ThrowHelper.ThrowIndexOutOfRangeException();
- return ref Unsafe.Add(ref _pointer.Value, index);
- }
- }
-
- /// <summary>
- /// Returns a reference to the 0th element of the Span. If the Span is empty, returns null reference.
- /// It can be used for pinning and is required to support the use of span within a fixed statement.
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public ref T GetPinnableReference()
- {
- // Ensure that the native code has just one forward branch that is predicted-not-taken.
- ref T ret = ref Unsafe.NullRef<T>();
- if (_length != 0) ret = ref _pointer.Value;
- return ref ret;
- }
-
- /// <summary>
- /// Clears the contents of this span.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Clear()
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- {
- SpanHelpers.ClearWithReferences(ref Unsafe.As<T, IntPtr>(ref _pointer.Value), (nuint)_length * (nuint)(Unsafe.SizeOf<T>() / sizeof(nuint)));
- }
- else
- {
- SpanHelpers.ClearWithoutReferences(ref Unsafe.As<T, byte>(ref _pointer.Value), (nuint)_length * (nuint)Unsafe.SizeOf<T>());
- }
- }
-
- /// <summary>
- /// Fills the contents of this span with the given value.
- /// </summary>
- public void Fill(T value)
- {
- if (Unsafe.SizeOf<T>() == 1)
- {
- uint length = (uint)_length;
- if (length == 0)
- return;
-
- T tmp = value; // Avoid taking address of the "value" argument. It would regress performance of the loop below.
- Unsafe.InitBlockUnaligned(ref Unsafe.As<T, byte>(ref _pointer.Value), Unsafe.As<T, byte>(ref tmp), length);
- }
- else
- {
- // Do all math as nuint to avoid unnecessary 64->32->64 bit integer truncations
- nuint length = (uint)_length;
- if (length == 0)
- return;
-
- ref T r = ref _pointer.Value;
-
- // TODO: Create block fill for value types of power of two sizes e.g. 2,4,8,16
-
- nuint elementSize = (uint)Unsafe.SizeOf<T>();
- nuint i = 0;
- for (; i < (length & ~(nuint)7); i += 8)
- {
- Unsafe.AddByteOffset<T>(ref r, (i + 0) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 1) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 2) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 3) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 4) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 5) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 6) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 7) * elementSize) = value;
- }
- if (i < (length & ~(nuint)3))
- {
- Unsafe.AddByteOffset<T>(ref r, (i + 0) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 1) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 2) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 3) * elementSize) = value;
- i += 4;
- }
- for (; i < length; i++)
- {
- Unsafe.AddByteOffset<T>(ref r, i * elementSize) = value;
- }
- }
- }
-
- /// <summary>
- /// Copies the contents of this span into destination span. If the source
- /// and destinations overlap, this method behaves as if the original values in
- /// a temporary location before the destination is overwritten.
- /// </summary>
- /// <param name="destination">The span to copy items into.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when the destination Span is shorter than the source Span.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void CopyTo(Span<T> destination)
- {
- // Using "if (!TryCopyTo(...))" results in two branches: one for the length
- // check, and one for the result of TryCopyTo. Since these checks are equivalent,
- // we can optimize by performing the check once ourselves then calling Memmove directly.
-
- if ((uint)_length <= (uint)destination.Length)
- {
- Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length);
- }
- else
- {
- ThrowHelper.ThrowArgumentException_DestinationTooShort();
- }
- }
-
- /// <summary>
- /// Copies the contents of this span into destination span. If the source
- /// and destinations overlap, this method behaves as if the original values in
- /// a temporary location before the destination is overwritten.
- /// </summary>
- /// <param name="destination">The span to copy items into.</param>
- /// <returns>If the destination span is shorter than the source span, this method
- /// return false and no data is written to the destination.</returns>
- public bool TryCopyTo(Span<T> destination)
- {
- bool retVal = false;
- if ((uint)_length <= (uint)destination.Length)
- {
- Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length);
- retVal = true;
- }
- return retVal;
- }
-
- /// <summary>
- /// Returns true if left and right point at the same memory and have the same length. Note that
- /// this does *not* check to see if the *contents* are equal.
- /// </summary>
- public static bool operator ==(Span<T> left, Span<T> right) =>
- left._length == right._length &&
- Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
-
- /// <summary>
- /// Defines an implicit conversion of a <see cref="Span{T}"/> to a <see cref="ReadOnlySpan{T}"/>
- /// </summary>
- public static implicit operator ReadOnlySpan<T>(Span<T> span) =>
- new ReadOnlySpan<T>(ref span._pointer.Value, span._length);
-
- /// <summary>
- /// For <see cref="Span{Char}"/>, returns a new instance of string that represents the characters pointed to by the span.
- /// Otherwise, returns a <see cref="string"/> with the name of the type and the number of elements.
- /// </summary>
- public override string ToString()
- {
- if (typeof(T) == typeof(char))
- {
- return new string(new ReadOnlySpan<char>(ref Unsafe.As<T, char>(ref _pointer.Value), _length));
- }
-#if FEATURE_UTF8STRING
- else if (typeof(T) == typeof(Char8))
- {
- // TODO_UTF8STRING: Call into optimized transcoding routine when it's available.
- return Encoding.UTF8.GetString(new ReadOnlySpan<byte>(ref Unsafe.As<T, byte>(ref _pointer.Value), _length));
- }
-#endif // FEATURE_UTF8STRING
- return string.Format("System.Span<{0}>[{1}]", typeof(T).Name, _length);
- }
-
- /// <summary>
- /// Forms a slice out of the given span, beginning at 'start'.
- /// </summary>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index is not in range (<0 or >Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Span<T> Slice(int start)
- {
- if ((uint)start > (uint)_length)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- return new Span<T>(ref Unsafe.Add(ref _pointer.Value, start), _length - start);
- }
-
- /// <summary>
- /// Forms a slice out of the given span, beginning at 'start', of given length
- /// </summary>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <param name="length">The desired length for the slice (exclusive).</param>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in range (<0 or >Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Span<T> Slice(int start, int length)
- {
-#if BIT64
- // Since start and length are both 32-bit, their sum can be computed across a 64-bit domain
- // without loss of fidelity. The cast to uint before the cast to ulong ensures that the
- // extension from 32- to 64-bit is zero-extending rather than sign-extending. The end result
- // of this is that if either input is negative or if the input sum overflows past Int32.MaxValue,
- // that information is captured correctly in the comparison against the backing _length field.
- // We don't use this same mechanism in a 32-bit process due to the overhead of 64-bit arithmetic.
- if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)_length)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-#else
- if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
- ThrowHelper.ThrowArgumentOutOfRangeException();
-#endif
-
- return new Span<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
- }
-
- /// <summary>
- /// Copies the contents of this span into a new array. This heap
- /// allocates, so should generally be avoided, however it is sometimes
- /// necessary to bridge the gap with APIs written in terms of arrays.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public T[] ToArray()
- {
- if (_length == 0)
- return Array.Empty<T>();
-
- var destination = new T[_length];
- Buffer.Memmove(ref Unsafe.As<byte, T>(ref destination.GetRawSzArrayData()), ref _pointer.Value, (nuint)_length);
- return destination;
- }
- }
-}
// 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.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
-
using System.Runtime.Versioning;
+using System.Text;
+using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
+using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
+using Internal.Runtime.CompilerServices;
#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
+#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif
+
namespace System
{
/// <summary>
/// </summary>
[DebuggerTypeProxy(typeof(SpanDebugView<>))]
[DebuggerDisplay("{ToString(),raw}")]
- public readonly ref partial struct Span<T>
+ [NonVersionable]
+ public readonly ref struct Span<T>
{
+ /// <summary>A byref or a native ptr.</summary>
+ internal readonly ByReference<T> _pointer;
+ /// <summary>The number of elements this Span contains.</summary>
+ private readonly int _length;
+
+ /// <summary>
+ /// Creates a new span over the entirety of the target array.
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span(T[]? array)
+ {
+ if (array == null)
+ {
+ this = default;
+ return; // returns default
+ }
+ if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
+ ThrowHelper.ThrowArrayTypeMismatchException();
+
+ _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()));
+ _length = array.Length;
+ }
+
+ /// <summary>
+ /// Creates a new span over the portion of the target array beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <param name="start">The index at which to begin the span.</param>
+ /// <param name="length">The number of items in the span.</param>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (<0 or >Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span(T[]? array, int start, int length)
+ {
+ if (array == null)
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+ this = default;
+ return; // returns default
+ }
+ if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
+ ThrowHelper.ThrowArrayTypeMismatchException();
+#if BIT64
+ // See comment in Span<T>.Slice for how this works.
+ if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)array.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+#else
+ if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+#endif
+
+ _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
+ _length = length;
+ }
+
+ /// <summary>
+ /// Creates a new span over the target unmanaged buffer. Clearly this
+ /// is quite dangerous, because we are creating arbitrarily typed T's
+ /// out of a void*-typed block of memory. And the length is not checked.
+ /// But if this creation is correct, then all subsequent uses are correct.
+ /// </summary>
+ /// <param name="pointer">An unmanaged pointer to memory.</param>
+ /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> is reference type or contains pointers and hence cannot be stored in unmanaged memory.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="length"/> is negative.
+ /// </exception>
+ [CLSCompliant(false)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe Span(void* pointer, int length)
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+ if (length < 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
+ _length = length;
+ }
+
+ // Constructor for internal use only.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal Span(ref T ptr, int length)
+ {
+ Debug.Assert(length >= 0);
+
+ _pointer = new ByReference<T>(ref ptr);
+ _length = length;
+ }
+
+ /// <summary>
+ /// Returns a reference to specified element of the Span.
+ /// </summary>
+ /// <param name="index"></param>
+ /// <returns></returns>
+ /// <exception cref="System.IndexOutOfRangeException">
+ /// Thrown when index less than 0 or index greater than or equal to Length
+ /// </exception>
+ public ref T this[int index]
+ {
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [NonVersionable]
+ get
+ {
+ if ((uint)index >= (uint)_length)
+ ThrowHelper.ThrowIndexOutOfRangeException();
+ return ref Unsafe.Add(ref _pointer.Value, index);
+ }
+ }
+
/// <summary>
/// The number of items in the span.
/// </summary>
get => ref _span[_index];
}
}
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the Span. If the Span is empty, returns null reference.
+ /// It can be used for pinning and is required to support the use of span within a fixed statement.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ref T GetPinnableReference()
+ {
+ // Ensure that the native code has just one forward branch that is predicted-not-taken.
+ ref T ret = ref Unsafe.NullRef<T>();
+ if (_length != 0) ret = ref _pointer.Value;
+ return ref ret;
+ }
+
+ /// <summary>
+ /// Clears the contents of this span.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Clear()
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ {
+ SpanHelpers.ClearWithReferences(ref Unsafe.As<T, IntPtr>(ref _pointer.Value), (nuint)_length * (nuint)(Unsafe.SizeOf<T>() / sizeof(nuint)));
+ }
+ else
+ {
+ SpanHelpers.ClearWithoutReferences(ref Unsafe.As<T, byte>(ref _pointer.Value), (nuint)_length * (nuint)Unsafe.SizeOf<T>());
+ }
+ }
+
+ /// <summary>
+ /// Fills the contents of this span with the given value.
+ /// </summary>
+ public void Fill(T value)
+ {
+ if (Unsafe.SizeOf<T>() == 1)
+ {
+ uint length = (uint)_length;
+ if (length == 0)
+ return;
+
+ T tmp = value; // Avoid taking address of the "value" argument. It would regress performance of the loop below.
+ Unsafe.InitBlockUnaligned(ref Unsafe.As<T, byte>(ref _pointer.Value), Unsafe.As<T, byte>(ref tmp), length);
+ }
+ else
+ {
+ // Do all math as nuint to avoid unnecessary 64->32->64 bit integer truncations
+ nuint length = (uint)_length;
+ if (length == 0)
+ return;
+
+ ref T r = ref _pointer.Value;
+
+ // TODO: Create block fill for value types of power of two sizes e.g. 2,4,8,16
+
+ nuint elementSize = (uint)Unsafe.SizeOf<T>();
+ nuint i = 0;
+ for (; i < (length & ~(nuint)7); i += 8)
+ {
+ Unsafe.AddByteOffset<T>(ref r, (i + 0) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 1) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 2) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 3) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 4) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 5) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 6) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 7) * elementSize) = value;
+ }
+ if (i < (length & ~(nuint)3))
+ {
+ Unsafe.AddByteOffset<T>(ref r, (i + 0) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 1) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 2) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 3) * elementSize) = value;
+ i += 4;
+ }
+ for (; i < length; i++)
+ {
+ Unsafe.AddByteOffset<T>(ref r, i * elementSize) = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Copies the contents of this span into destination span. If the source
+ /// and destinations overlap, this method behaves as if the original values in
+ /// a temporary location before the destination is overwritten.
+ /// </summary>
+ /// <param name="destination">The span to copy items into.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when the destination Span is shorter than the source Span.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void CopyTo(Span<T> destination)
+ {
+ // Using "if (!TryCopyTo(...))" results in two branches: one for the length
+ // check, and one for the result of TryCopyTo. Since these checks are equivalent,
+ // we can optimize by performing the check once ourselves then calling Memmove directly.
+
+ if ((uint)_length <= (uint)destination.Length)
+ {
+ Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length);
+ }
+ else
+ {
+ ThrowHelper.ThrowArgumentException_DestinationTooShort();
+ }
+ }
+
+ /// <summary>
+ /// Copies the contents of this span into destination span. If the source
+ /// and destinations overlap, this method behaves as if the original values in
+ /// a temporary location before the destination is overwritten.
+ /// </summary>
+ /// <param name="destination">The span to copy items into.</param>
+ /// <returns>If the destination span is shorter than the source span, this method
+ /// return false and no data is written to the destination.</returns>
+ public bool TryCopyTo(Span<T> destination)
+ {
+ bool retVal = false;
+ if ((uint)_length <= (uint)destination.Length)
+ {
+ Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length);
+ retVal = true;
+ }
+ return retVal;
+ }
+
+ /// <summary>
+ /// Returns true if left and right point at the same memory and have the same length. Note that
+ /// this does *not* check to see if the *contents* are equal.
+ /// </summary>
+ public static bool operator ==(Span<T> left, Span<T> right) =>
+ left._length == right._length &&
+ Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
+
+ /// <summary>
+ /// Defines an implicit conversion of a <see cref="Span{T}"/> to a <see cref="ReadOnlySpan{T}"/>
+ /// </summary>
+ public static implicit operator ReadOnlySpan<T>(Span<T> span) =>
+ new ReadOnlySpan<T>(ref span._pointer.Value, span._length);
+
+ /// <summary>
+ /// For <see cref="Span{Char}"/>, returns a new instance of string that represents the characters pointed to by the span.
+ /// Otherwise, returns a <see cref="string"/> with the name of the type and the number of elements.
+ /// </summary>
+ public override string ToString()
+ {
+ if (typeof(T) == typeof(char))
+ {
+ return new string(new ReadOnlySpan<char>(ref Unsafe.As<T, char>(ref _pointer.Value), _length));
+ }
+#if FEATURE_UTF8STRING
+ else if (typeof(T) == typeof(Char8))
+ {
+ // TODO_UTF8STRING: Call into optimized transcoding routine when it's available.
+ return Encoding.UTF8.GetString(new ReadOnlySpan<byte>(ref Unsafe.As<T, byte>(ref _pointer.Value), _length));
+ }
+#endif // FEATURE_UTF8STRING
+ return string.Format("System.Span<{0}>[{1}]", typeof(T).Name, _length);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given span, beginning at 'start'.
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index is not in range (<0 or >Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span<T> Slice(int start)
+ {
+ if ((uint)start > (uint)_length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new Span<T>(ref Unsafe.Add(ref _pointer.Value, start), _length - start);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given span, beginning at 'start', of given length
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="length">The desired length for the slice (exclusive).</param>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in range (<0 or >Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span<T> Slice(int start, int length)
+ {
+#if BIT64
+ // Since start and length are both 32-bit, their sum can be computed across a 64-bit domain
+ // without loss of fidelity. The cast to uint before the cast to ulong ensures that the
+ // extension from 32- to 64-bit is zero-extending rather than sign-extending. The end result
+ // of this is that if either input is negative or if the input sum overflows past Int32.MaxValue,
+ // that information is captured correctly in the comparison against the backing _length field.
+ // We don't use this same mechanism in a 32-bit process due to the overhead of 64-bit arithmetic.
+ if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)_length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+#else
+ if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+#endif
+
+ return new Span<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
+ }
+
+ /// <summary>
+ /// Copies the contents of this span into a new array. This heap
+ /// allocates, so should generally be avoided, however it is sometimes
+ /// necessary to bridge the gap with APIs written in terms of arrays.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public T[] ToArray()
+ {
+ if (_length == 0)
+ return Array.Empty<T>();
+
+ var destination = new T[_length];
+ Buffer.Memmove(ref Unsafe.As<byte, T>(ref destination.GetRawSzArrayData()), ref _pointer.Value, (nuint)_length);
+ return destination;
+ }
}
}