Consolidate *.Fast.cs (dotnet/coreclr#27644)
authorJan Kotas <jkotas@microsoft.com>
Sun, 3 Nov 2019 11:55:42 +0000 (03:55 -0800)
committerStephen Toub <stoub@microsoft.com>
Sun, 3 Nov 2019 11:55:42 +0000 (06:55 -0500)
System.Memory OOB package that this split was originally done for does not exist anymore.

Commit migrated from https://github.com/dotnet/coreclr/commit/8352294d22832a59136201d7eec455724891f593

src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.Globalization.cs [moved from src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.Fast.cs with 63% similarity]
src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs
src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.Fast.cs [deleted file]
src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.Fast.cs [deleted file]
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs
src/libraries/System.Private.CoreLib/src/System/Span.Fast.cs [deleted file]
src/libraries/System.Private.CoreLib/src/System/Span.cs

index a62c3c8..1f05361 100644 (file)
     <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" />
@@ -1,4 +1,4 @@
-// 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.
 
@@ -6,17 +6,26 @@ using System.Diagnostics;
 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>
@@ -383,244 +392,25 @@ namespace System
         }
 
         /// <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 (&lt;0 or &gt;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 (&lt;0 or &gt;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);
         }
     }
 }
index 81b7bef..227b2a9 100644 (file)
@@ -5,7 +5,6 @@
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
-using System.Text;
 
 using Internal.Runtime.CompilerServices;
 
@@ -24,16 +23,244 @@ namespace System
     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 (&lt;0 or &gt;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 (&lt;0 or &gt;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>
@@ -991,28 +1218,6 @@ namespace System
         }
 
         /// <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)
diff --git a/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.Fast.cs b/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.Fast.cs
deleted file mode 100644 (file)
index 238b90f..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-// 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 (&lt;0 or &gt;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 (&lt;0 or &gt;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 (&lt;0 or &gt;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;
-        }
-    }
-}
index 9a3f49f..94cc4d2 100644 (file)
@@ -2,14 +2,23 @@
 // 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>
@@ -18,8 +27,124 @@ namespace System
     /// </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 (&lt;0 or &gt;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>
@@ -123,5 +248,146 @@ namespace System
                 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 (&lt;0 or &gt;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 (&lt;0 or &gt;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;
+        }
     }
 }
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.Fast.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.Fast.cs
deleted file mode 100644 (file)
index e3cf0a8..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-// 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);
-    }
-}
index 094486b..a61e022 100644 (file)
@@ -16,9 +16,225 @@ namespace System.Runtime.InteropServices
     /// 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>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Span.Fast.cs b/src/libraries/System.Private.CoreLib/src/System/Span.Fast.cs
deleted file mode 100644 (file)
index 2ecd1cc..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-// 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 (&lt;0 or &gt;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 (&lt;0 or &gt;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 (&lt;0 or &gt;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;
-        }
-    }
-}
index 244d534..149107b 100644 (file)
@@ -2,14 +2,23 @@
 // 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>
@@ -18,8 +27,130 @@ namespace System
     /// </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 (&lt;0 or &gt;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>
@@ -123,5 +254,226 @@ namespace System
                 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 (&lt;0 or &gt;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 (&lt;0 or &gt;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;
+        }
     }
 }