Move Span/ReadOnlySpan to shared CoreLib partition (#10988)
authorJan Kotas <jkotas@microsoft.com>
Sat, 15 Apr 2017 20:32:58 +0000 (13:32 -0700)
committerGitHub <noreply@github.com>
Sat, 15 Apr 2017 20:32:58 +0000 (13:32 -0700)
Fix a few method names to better names used in CoreRT

Contributes to https://github.com/dotnet/corert/issues/2966

src/mscorlib/System.Private.CoreLib.csproj
src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
src/mscorlib/shared/System/ReadOnlySpan.cs [moved from src/mscorlib/src/System/ReadOnlySpan.cs with 96% similarity]
src/mscorlib/shared/System/Span.NonGeneric.cs [moved from src/mscorlib/src/System/Span.cs with 55% similarity]
src/mscorlib/shared/System/Span.cs [new file with mode: 0644]
src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs
src/mscorlib/src/System/String.cs
src/vm/jitinterface.cpp
src/vm/mscorlib.h

index 4541ef8..df86533 100644 (file)
     <Compile Condition="'$(FeatureCominterop)' == 'true'" Include="$(BclSourcesRoot)\System\Variant.cs" />
     <Compile Condition="'$(FeatureClassicCominterop)' == 'true'" Include="$(BclSourcesRoot)\System\OleAutBinder.cs" />
     <Compile Include="$(BclSourcesRoot)\System\ByReference.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Span.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\ReadOnlySpan.cs" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="$(BclSourcesRoot)\Internal\Runtime\Augments\EnvironmentAugments.cs" />
index 6ef7fc1..d56b7e1 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)System\Progress.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\Random.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\RankException.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\ReadOnlySpan.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\Reflection\AmbiguousMatchException.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Assembly.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Reflection\AssemblyAlgorithmIdAttribute.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\SuppressUnmanagedCodeSecurityAttribute.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\UnverifiableCodeAttribute.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\Security\VerificationException.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Span.cs"/>
+    <Compile Include="$(MSBuildThisFileDirectory)System\Span.NonGeneric.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\StackOverflowException.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\StringComparer.cs"/>
     <Compile Include="$(MSBuildThisFileDirectory)System\StringComparison.cs"/>
similarity index 96%
rename from src/mscorlib/src/System/ReadOnlySpan.cs
rename to src/mscorlib/shared/System/ReadOnlySpan.cs
index 8d0fbad..35d4c4f 100644 (file)
@@ -34,7 +34,7 @@ namespace System
             if (array == null)
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
 
-            _pointer = new ByReference<T>(ref JitHelpers.GetArrayData(array));
+            _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()));
             _length = array.Length;
         }
 
@@ -57,7 +57,7 @@ namespace System
             if ((uint)start > (uint)array.Length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            _pointer = new ByReference<T>(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
+            _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
             _length = array.Length - start;
         }
 
@@ -81,7 +81,7 @@ namespace System
             if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            _pointer = new ByReference<T>(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
+            _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
             _length = length;
         }
 
@@ -202,7 +202,7 @@ namespace System
             if ((uint)_length > (uint)destination.Length)
                 return false;
 
-            SpanHelper.CopyTo<T>(ref destination.DangerousGetPinnableReference(), ref _pointer.Value, _length);
+            Span.CopyTo<T>(ref destination.DangerousGetPinnableReference(), ref _pointer.Value, _length);
             return true;
         }
 
@@ -301,7 +301,7 @@ namespace System
                 return Array.Empty<T>();
 
             var destination = new T[_length];
-            SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref _pointer.Value, _length);
+            Span.CopyTo<T>(ref Unsafe.As<byte, T>(ref destination.GetRawSzArrayData()), ref _pointer.Value, _length);
             return destination;
         }
 
similarity index 55%
rename from src/mscorlib/src/System/Span.cs
rename to src/mscorlib/shared/System/Span.NonGeneric.cs
index 4211083..acae5e4 100644 (file)
@@ -5,11 +5,6 @@
 using System.Diagnostics;
 using System.Runtime;
 using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
-using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
-
-#pragma warning disable 0809  //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
 
 #if BIT64
 using nuint = System.UInt64;
@@ -20,388 +15,8 @@ using nuint = System.UInt32;
 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.
+    /// Extension methods and non-generic helpers for Span and ReadOnlySpan
     /// </summary>
-    public struct Span<T>
-    {
-        /// <summary>A byref or a native ptr.</summary>
-        private 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>
-        /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
-        /// reference (Nothing in Visual Basic).</exception>
-        /// <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)
-                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
-            if (default(T) == null && array.GetType() != typeof(T[]))
-                ThrowHelper.ThrowArrayTypeMismatchException();
-
-            _pointer = new ByReference<T>(ref JitHelpers.GetArrayData(array));
-            _length = array.Length;
-        }
-
-        /// <summary>
-        /// Creates a new span over the portion of the target array beginning
-        /// at 'start' index and covering the remainder of the array.
-        /// </summary>
-        /// <param name="array">The target array.</param>
-        /// <param name="start">The index at which to begin the span.</param>
-        /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
-        /// reference (Nothing in Visual Basic).</exception>
-        /// <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"/> is not in the range (&lt;0 or &gt;=Length).
-        /// </exception>
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public Span(T[] array, int start)
-        {
-            if (array == null)
-                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
-            if (default(T) == null && array.GetType() != typeof(T[]))
-                ThrowHelper.ThrowArrayTypeMismatchException();
-            if ((uint)start > (uint)array.Length)
-                ThrowHelper.ThrowArgumentOutOfRangeException();
-
-            _pointer = new ByReference<T>(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
-            _length = array.Length - start;
-        }
-
-        /// <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>
-        /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
-        /// reference (Nothing in Visual Basic).</exception>
-        /// <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)
-                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
-            if (default(T) == null && array.GetType() != typeof(T[]))
-                ThrowHelper.ThrowArrayTypeMismatchException();
-            if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
-                ThrowHelper.ThrowArgumentOutOfRangeException();
-
-            _pointer = new ByReference<T>(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), 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;
-        }
-
-        /// <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 neither the
-        /// <paramref name="length"/> is checked, nor <paramref name="obj"/> being null, nor the fact that
-        /// "rawPointer" actually lies within <paramref name="obj"/>.
-        /// </summary>
-        /// <param name="obj">The managed object that contains the data to span over.</param>
-        /// <param name="objectData">A reference to data within that object.</param>
-        /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static Span<T> DangerousCreate(object obj, ref T objectData, int length) => new Span<T>(ref objectData, 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 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 can be used for pinning but must never be dereferenced.
-        /// </summary>
-        public ref T DangerousGetPinnableReference()
-        {
-            return ref _pointer.Value;
-        }
-
-        /// <summary>
-        /// The number of items in the span.
-        /// </summary>
-        public int Length => _length;
-
-        /// <summary>
-        /// Returns true if Length is 0.
-        /// </summary>
-        public bool IsEmpty => _length == 0;
-
-        /// <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]
-        {
-            [MethodImpl(MethodImplOptions.AggressiveInlining)]
-            get
-            {
-                if ((uint)index >= (uint)_length)
-                    ThrowHelper.ThrowIndexOutOfRangeException();
-
-                return ref Unsafe.Add(ref _pointer.Value, index);
-            }
-        }
-
-        /// <summary>
-        /// Clears the contents of this span.
-        /// </summary>
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public void Clear()
-        {
-            if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
-            {
-                SpanHelper.ClearWithReferences(ref Unsafe.As<T, IntPtr>(ref _pointer.Value), (nuint)_length * (nuint)(Unsafe.SizeOf<T>() / sizeof(nuint)));
-            }
-            else
-            {
-                SpanHelper.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 DangerousGetPinnableReference();
-
-                // 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>
-        public void CopyTo(Span<T> destination)
-        {
-            if (!TryCopyTo(destination))
-                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)
-        {
-            if ((uint)_length > (uint)destination.Length)
-                return false;
-
-            SpanHelper.CopyTo<T>(ref destination._pointer.Value, ref _pointer.Value, _length);
-            return true;
-        }
-
-        /// <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)
-        {
-            return left._length == right._length && Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
-        }
-
-        /// <summary>
-        /// Returns false 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 == right);
-
-        /// <summary>
-        /// This method is not supported as spans cannot be boxed. To compare two spans, use operator==.
-        /// <exception cref="System.NotSupportedException">
-        /// Always thrown by this method.
-        /// </exception>
-        /// </summary>
-        [Obsolete("Equals() on Span will always throw an exception. Use == instead.")]
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override bool Equals(object obj)
-        {
-            throw new NotSupportedException(SR.NotSupported_CannotCallEqualsOnSpan);
-        }
-
-        /// <summary>
-        /// This method is not supported as spans cannot be boxed.
-        /// <exception cref="System.NotSupportedException">
-        /// Always thrown by this method.
-        /// </exception>
-        /// </summary>
-        [Obsolete("GetHashCode() on Span will always throw an exception.")]
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override int GetHashCode()
-        {
-            throw new NotSupportedException(SR.NotSupported_CannotCallGetHashCodeOnSpan);
-        }
-
-        /// <summary>
-        /// Defines an implicit conversion of an array to a <see cref="Span{T}"/>
-        /// </summary>
-        public static implicit operator Span<T>(T[] array) => new Span<T>(array);
-
-        /// <summary>
-        /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="Span{T}"/>
-        /// </summary>
-        public static implicit operator Span<T>(ArraySegment<T> arraySegment) => new Span<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
-
-        /// <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>
-        /// 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 ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
-                ThrowHelper.ThrowArgumentOutOfRangeException();
-
-            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];
-            SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref _pointer.Value, _length);
-            return destination;
-        }
-
-        // <summary>
-        /// Returns an empty <see cref="Span{T}"/>
-        /// </summary>
-        public static Span<T> Empty => default(Span<T>);
-    }
-
     public static class Span
     {
         /// <summary>
@@ -508,12 +123,9 @@ namespace System
             if (text == null)
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
 
-            return new ReadOnlySpan<char>(ref text.GetFirstCharRef(), text.Length);
+            return new ReadOnlySpan<char>(ref text.GetRawStringData(), text.Length);
         }
-    }
 
-    internal static class SpanHelper
-    {
         internal static unsafe void CopyTo<T>(ref T destination, ref T source, int elementsCount)
         {
             if (Unsafe.AreSame(ref destination, ref source))
diff --git a/src/mscorlib/shared/System/Span.cs b/src/mscorlib/shared/System/Span.cs
new file mode 100644 (file)
index 0000000..913c4a2
--- /dev/null
@@ -0,0 +1,403 @@
+// 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;
+using System.Runtime.CompilerServices;
+using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
+using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
+
+#pragma warning disable 0809  //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
+
+#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>
+    public struct Span<T>
+    {
+        /// <summary>A byref or a native ptr.</summary>
+        private 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>
+        /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
+        /// reference (Nothing in Visual Basic).</exception>
+        /// <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)
+                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+            if (default(T) == null && array.GetType() != typeof(T[]))
+                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 covering the remainder of the array.
+        /// </summary>
+        /// <param name="array">The target array.</param>
+        /// <param name="start">The index at which to begin the span.</param>
+        /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
+        /// reference (Nothing in Visual Basic).</exception>
+        /// <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"/> is not in the range (&lt;0 or &gt;=Length).
+        /// </exception>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public Span(T[] array, int start)
+        {
+            if (array == null)
+                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+            if (default(T) == null && array.GetType() != typeof(T[]))
+                ThrowHelper.ThrowArrayTypeMismatchException();
+            if ((uint)start > (uint)array.Length)
+                ThrowHelper.ThrowArgumentOutOfRangeException();
+
+            _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
+            _length = array.Length - start;
+        }
+
+        /// <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>
+        /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
+        /// reference (Nothing in Visual Basic).</exception>
+        /// <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)
+                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+            if (default(T) == null && array.GetType() != typeof(T[]))
+                ThrowHelper.ThrowArrayTypeMismatchException();
+            if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
+                ThrowHelper.ThrowArgumentOutOfRangeException();
+
+            _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;
+        }
+
+        /// <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 neither the
+        /// <paramref name="length"/> is checked, nor <paramref name="obj"/> being null, nor the fact that
+        /// "rawPointer" actually lies within <paramref name="obj"/>.
+        /// </summary>
+        /// <param name="obj">The managed object that contains the data to span over.</param>
+        /// <param name="objectData">A reference to data within that object.</param>
+        /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static Span<T> DangerousCreate(object obj, ref T objectData, int length) => new Span<T>(ref objectData, 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 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 can be used for pinning but must never be dereferenced.
+        /// </summary>
+        public ref T DangerousGetPinnableReference()
+        {
+            return ref _pointer.Value;
+        }
+
+        /// <summary>
+        /// The number of items in the span.
+        /// </summary>
+        public int Length => _length;
+
+        /// <summary>
+        /// Returns true if Length is 0.
+        /// </summary>
+        public bool IsEmpty => _length == 0;
+
+        /// <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]
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get
+            {
+                if ((uint)index >= (uint)_length)
+                    ThrowHelper.ThrowIndexOutOfRangeException();
+
+                return ref Unsafe.Add(ref _pointer.Value, index);
+            }
+        }
+
+        /// <summary>
+        /// Clears the contents of this span.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public void Clear()
+        {
+            if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+            {
+                Span.ClearWithReferences(ref Unsafe.As<T, IntPtr>(ref _pointer.Value), (nuint)_length * (nuint)(Unsafe.SizeOf<T>() / sizeof(nuint)));
+            }
+            else
+            {
+                Span.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 DangerousGetPinnableReference();
+
+                // 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>
+        public void CopyTo(Span<T> destination)
+        {
+            if (!TryCopyTo(destination))
+                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)
+        {
+            if ((uint)_length > (uint)destination.Length)
+                return false;
+
+            Span.CopyTo<T>(ref destination._pointer.Value, ref _pointer.Value, _length);
+            return true;
+        }
+
+        /// <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)
+        {
+            return left._length == right._length && Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
+        }
+
+        /// <summary>
+        /// Returns false 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 == right);
+
+        /// <summary>
+        /// This method is not supported as spans cannot be boxed. To compare two spans, use operator==.
+        /// <exception cref="System.NotSupportedException">
+        /// Always thrown by this method.
+        /// </exception>
+        /// </summary>
+        [Obsolete("Equals() on Span will always throw an exception. Use == instead.")]
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override bool Equals(object obj)
+        {
+            throw new NotSupportedException(SR.NotSupported_CannotCallEqualsOnSpan);
+        }
+
+        /// <summary>
+        /// This method is not supported as spans cannot be boxed.
+        /// <exception cref="System.NotSupportedException">
+        /// Always thrown by this method.
+        /// </exception>
+        /// </summary>
+        [Obsolete("GetHashCode() on Span will always throw an exception.")]
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override int GetHashCode()
+        {
+            throw new NotSupportedException(SR.NotSupported_CannotCallGetHashCodeOnSpan);
+        }
+
+        /// <summary>
+        /// Defines an implicit conversion of an array to a <see cref="Span{T}"/>
+        /// </summary>
+        public static implicit operator Span<T>(T[] array) => new Span<T>(array);
+
+        /// <summary>
+        /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="Span{T}"/>
+        /// </summary>
+        public static implicit operator Span<T>(ArraySegment<T> arraySegment) => new Span<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
+
+        /// <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>
+        /// 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 ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
+                ThrowHelper.ThrowArgumentOutOfRangeException();
+
+            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];
+            Span.CopyTo<T>(ref Unsafe.As<byte, T>(ref destination.GetRawSzArrayData()), ref _pointer.Value, _length);
+            return destination;
+        }
+
+        // <summary>
+        /// Returns an empty <see cref="Span{T}"/>
+        /// </summary>
+        public static Span<T> Empty => default(Span<T>);
+    }
+}
index b86835f..d520135 100644 (file)
@@ -216,14 +216,7 @@ namespace System.Runtime.CompilerServices
         private extern static bool IsAddressInStack(IntPtr ptr);
 #endif
 
-        static internal bool ByRefLessThan<T>(ref T refA, ref T refB)
-        {
-            // The body of this function will be replaced by the EE with unsafe code!!!
-            // See getILIntrinsicImplementation for how this happens.
-            throw new InvalidOperationException();
-        }
-
-        static internal ref T GetArrayData<T>(T[] array)
+        static internal ref byte GetRawSzArrayData(this Array array)
         {
             // The body of this function will be replaced by the EE with unsafe code!!!
             // See getILIntrinsicImplementation for how this happens.
index f3a4d0f..0a17c1e 100644 (file)
@@ -876,7 +876,7 @@ namespace System
             }
         }
 
-        internal ref char GetFirstCharRef()
+        internal ref char GetRawStringData()
         {
             return ref m_firstChar;
         }
index 338c274..a82cf00 100644 (file)
@@ -6921,18 +6921,7 @@ bool getILIntrinsicImplementation(MethodDesc * ftn,
             return true;
         }
     }
-    else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__BYREF_LESSTHAN)->GetMemberDef())
-    {
-        // Compare the two arguments
-        static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CLT & 0xFF), CEE_RET };
-        methInfo->ILCode = const_cast<BYTE*>(ilcode);
-        methInfo->ILCodeSize = sizeof(ilcode);
-        methInfo->maxStack = 2;
-        methInfo->EHcount = 0;
-        methInfo->options = (CorInfoOptions)0;
-        return true;
-    }
-    else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__GET_ARRAY_DATA)->GetMemberDef())
+    else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__GET_RAW_SZ_ARRAY_DATA)->GetMemberDef())
     {
         mdToken tokArrayPinningHelper = MscorlibBinder::GetField(FIELD__ARRAY_PINNING_HELPER__M_ARRAY_DATA)->GetMemberDef();
 
index 244b690..4b82de0 100644 (file)
@@ -805,8 +805,7 @@ DEFINE_METHOD(JIT_HELPERS,          UNSAFE_ENUM_CAST,       UnsafeEnumCast, NoSi
 DEFINE_METHOD(JIT_HELPERS,          UNSAFE_ENUM_CAST_LONG,  UnsafeEnumCastLong, NoSig)
 DEFINE_METHOD(JIT_HELPERS,          UNSAFE_CAST_TO_STACKPTR,UnsafeCastToStackPointer, NoSig)
 #endif // _DEBUG
-DEFINE_METHOD(JIT_HELPERS,          BYREF_LESSTHAN,         ByRefLessThan, NoSig)
-DEFINE_METHOD(JIT_HELPERS,          GET_ARRAY_DATA,         GetArrayData, NoSig)
+DEFINE_METHOD(JIT_HELPERS,          GET_RAW_SZ_ARRAY_DATA,  GetRawSzArrayData, NoSig)
 
 DEFINE_CLASS(UNSAFE,                CompilerServices,       Unsafe)
 DEFINE_METHOD(UNSAFE,               AS_POINTER,             AsPointer, NoSig)