diff --git a/pkg/Microsoft.Private.PackageBaseline/packageIndex.json b/pkg/Microsoft.Private.PackageBaseline/packageIndex.json
index c011be9f128a..3267aaada3da 100644
--- a/pkg/Microsoft.Private.PackageBaseline/packageIndex.json
+++ b/pkg/Microsoft.Private.PackageBaseline/packageIndex.json
@@ -1476,6 +1476,13 @@
"4.0.3.0": "4.4.0"
}
},
+ "System.Memory": {
+ "StableVersions": [
+ ],
+ "AssemblyVersionInPackageVersion": {
+ "4.0.0.0": "4.4.0"
+ }
+ },
"System.Net.Http": {
"StableVersions": [
"4.0.0",
@@ -2753,4 +2760,4 @@
"System.Security.Cryptography.Native.Apple": "runtime.native.System.Security.Cryptography.Apple",
"System.Security.Cryptography.Native.OpenSsl": "runtime.native.System.Security.Cryptography.OpenSsl"
}
-}
\ No newline at end of file
+}
diff --git a/pkg/descriptions.json b/pkg/descriptions.json
index 2654b9c5c86c..cddcf18a78ee 100644
--- a/pkg/descriptions.json
+++ b/pkg/descriptions.json
@@ -833,6 +833,13 @@
"System.Linq.EnumerableQuery"
]
},
+ {
+ "Name": "System.Memory",
+ "Description": "Provides types for efficient low-allocation access to memory.",
+ "CommonTypes": [
+ "System.Span",
+ ]
+ },
{
"Name": "System.Net.Http",
"Description": "Provides a programming interface for modern HTTP applications, including HTTP client components that allow applications to consume web services over HTTP and HTTP components that can be used by both clients and servers for parsing HTTP headers.",
@@ -1623,7 +1630,7 @@
"System.ServiceProcess.ServiceType"
]
},
- {
+ {
"Name": "System.Text.Encoding",
"Description": "Provides base abstract encoding classes for converting blocks of characters to and from blocks of bytes.",
"CommonTypes": [
diff --git a/src/System.Memory/System.Memory.sln b/src/System.Memory/System.Memory.sln
new file mode 100644
index 000000000000..9fcf61cee4c0
--- /dev/null
+++ b/src/System.Memory/System.Memory.sln
@@ -0,0 +1,27 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.25831.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Memory", "src\System.Memory.csproj", "{4BBC8F69-D03E-4432-AA8A-D458FA5B235A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Memory.Tests", "tests\System.Memory.Tests.csproj", "{15DC55FA-E644-4B87-A62A-DCF849031633}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {4BBC8F69-D03E-4432-AA8A-D458FA5B235A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4BBC8F69-D03E-4432-AA8A-D458FA5B235A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4BBC8F69-D03E-4432-AA8A-D458FA5B235A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4BBC8F69-D03E-4432-AA8A-D458FA5B235A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {15DC55FA-E644-4B87-A62A-DCF849031633}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {15DC55FA-E644-4B87-A62A-DCF849031633}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {15DC55FA-E644-4B87-A62A-DCF849031633}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {15DC55FA-E644-4B87-A62A-DCF849031633}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/src/System.Memory/pkg/System.Memory.builds b/src/System.Memory/pkg/System.Memory.builds
new file mode 100644
index 000000000000..ad45fd50758b
--- /dev/null
+++ b/src/System.Memory/pkg/System.Memory.builds
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/System.Memory/pkg/System.Memory.pkgproj b/src/System.Memory/pkg/System.Memory.pkgproj
new file mode 100644
index 000000000000..8200460e6481
--- /dev/null
+++ b/src/System.Memory/pkg/System.Memory.pkgproj
@@ -0,0 +1,10 @@
+
+
+
+
+
+ net45;netcore45;wp8;wpa81;netcoreapp1.0;$(AllXamarinFrameworks)
+
+
+
+
diff --git a/src/System.Memory/ref/System.Memory.builds b/src/System.Memory/ref/System.Memory.builds
new file mode 100644
index 000000000000..87b2f7a0539d
--- /dev/null
+++ b/src/System.Memory/ref/System.Memory.builds
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/System.Memory/ref/System.Memory.cs b/src/System.Memory/ref/System.Memory.cs
new file mode 100644
index 000000000000..5716a32bd98d
--- /dev/null
+++ b/src/System.Memory/ref/System.Memory.cs
@@ -0,0 +1,35 @@
+#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
+namespace System
+{
+ [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
+ public partial struct Span
+ {
+ public static readonly System.Span Empty;
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]public Span(T[] array) { throw null;}
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]public Span(T[] array, int start) { throw null;}
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]public Span(T[] array, int start, int length) { throw null;}
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]public unsafe Span(void* pointer, int length) { throw null;}
+ public bool IsEmpty { get { throw null; } }
+ public T this[int index] { [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]get { throw null; } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]set { throw null; }}
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]public ref T GetItem(int index) { throw null; }
+ public int Length { get { throw null; } }
+ public void CopyTo(System.Span destination) { }
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]public static System.Span DangerousCreate(object obj, ref T objectData, int length) { throw null; }
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]public ref T DangerousGetPinnableReference() { throw null; }
+ [System.ObsoleteAttribute("Equals() on Span will always throw an exception. Use == instead.")]
+ [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
+ public override bool Equals(object obj) { throw null; }
+ [System.ObsoleteAttribute("GetHashCode() on Span will always throw an exception.")]
+ [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
+ public override int GetHashCode() { throw null; }
+ public static bool operator ==(System.Span left, System.Span right) { throw null; }
+ public static implicit operator System.Span (T[] array) { throw null; }
+ public static implicit operator System.Span (System.ArraySegment arraySegment) { throw null; }
+ public static bool operator !=(System.Span left, System.Span right) { throw null; }
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]public System.Span Slice(int start) { throw null; }
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]public System.Span Slice(int start, int length) { throw null; }
+ public T[] ToArray() { throw null; }
+ public bool TryCopyTo(System.Span destination) { throw null; }
+ }
+}
+
diff --git a/src/System.Memory/ref/System.Memory.csproj b/src/System.Memory/ref/System.Memory.csproj
new file mode 100644
index 000000000000..f1256bbb3206
--- /dev/null
+++ b/src/System.Memory/ref/System.Memory.csproj
@@ -0,0 +1,19 @@
+
+
+
+
+ true
+ Library
+ false
+ 4.0.0.0
+ .NETStandard,Version=v1.0
+ {0EF9D369-7097-44F9-BEBA-C32AF5EB4756}
+
+
+
+
+
+
+
+
+
diff --git a/src/System.Memory/ref/project.json b/src/System.Memory/ref/project.json
new file mode 100644
index 000000000000..9bda63161248
--- /dev/null
+++ b/src/System.Memory/ref/project.json
@@ -0,0 +1,9 @@
+{
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "System.Runtime": "4.1.0"
+ },
+ "frameworks": {
+ "netstandard1.0": {}
+ }
+}
diff --git a/src/System.Memory/src/Resources/Strings.resx b/src/System.Memory/src/Resources/Strings.resx
new file mode 100644
index 000000000000..e5bc8b905b71
--- /dev/null
+++ b/src/System.Memory/src/Resources/Strings.resx
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ The array type must be exactly {0}.
+
+
+ Equals() on Span and ReadOnlySpan is not supported. Use operator== instead.
+
+
+ GetHashCode() on Span and ReadOnlySpan is not supported.
+
+
+ Cannot use type '{0}'. Only value types without pointers or references are supported.
+
+
+ Destination is too short.
+
+
diff --git a/src/System.Memory/src/System.Memory.builds b/src/System.Memory/src/System.Memory.builds
new file mode 100644
index 000000000000..441802d2477b
--- /dev/null
+++ b/src/System.Memory/src/System.Memory.builds
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/System.Memory/src/System.Memory.csproj b/src/System.Memory/src/System.Memory.csproj
new file mode 100644
index 000000000000..c0ddd27cf6e2
--- /dev/null
+++ b/src/System.Memory/src/System.Memory.csproj
@@ -0,0 +1,29 @@
+
+
+
+
+ {4BBC8F69-D03E-4432-AA8A-D458FA5B235A}
+ System.Memory
+ 4.0.0.0
+ true
+ false
+ .NETStandard,Version=v1.0
+ $(OutputPath)$(AssemblyName).xml
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/System.Memory/src/System/Pinnable.cs b/src/System.Memory/src/System/Pinnable.cs
new file mode 100644
index 000000000000..0f9b02ad94c6
--- /dev/null
+++ b/src/System.Memory/src/System/Pinnable.cs
@@ -0,0 +1,18 @@
+// 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.InteropServices;
+
+namespace System
+{
+ //
+ // This class exists solely so that arbitrary objects can be Unsafe-casted to it to get a ref to the start of the user data.
+ //
+ [StructLayout(LayoutKind.Sequential)]
+ internal sealed class Pinnable
+ {
+ public T Data;
+ }
+}
diff --git a/src/System.Memory/src/System/Span.cs b/src/System.Memory/src/System/Span.cs
new file mode 100644
index 000000000000..cf7a059216f4
--- /dev/null
+++ b/src/System.Memory/src/System/Span.cs
@@ -0,0 +1,431 @@
+// 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 EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
+using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
+
+#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
+
+namespace System
+{
+ ///
+ /// 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.
+ ///
+ public struct Span
+ {
+ ///
+ /// Creates a new span over the entirety of the target array.
+ ///
+ /// The target array.
+ /// Thrown when is a null
+ /// reference (Nothing in Visual Basic).
+ /// Thrown when is covariant and array's type is not exactly T[].
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span(T[] array)
+ {
+ if (array == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ if (default(T) == null && array.GetType() != typeof(T[]))
+ ThrowHelper.ThrowArrayTypeMismatchException_ArrayTypeMustBeExactMatch(typeof(T));
+
+ _length = array.Length;
+ _pinnable = Unsafe.As>(array);
+ _byteOffset = SpanHelpers.PerTypeValues.ArrayAdjustment;
+ }
+
+ ///
+ /// Creates a new span over the portion of the target array beginning
+ /// at 'start' index and covering the remainder of the array.
+ ///
+ /// The target array.
+ /// The index at which to begin the span.
+ /// Thrown when is a null
+ /// reference (Nothing in Visual Basic).
+ /// Thrown when is covariant and array's type is not exactly T[].
+ ///
+ /// Thrown when the specified is not in the range (<0 or >=Length).
+ ///
+ [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_ArrayTypeMustBeExactMatch(typeof(T));
+
+ int arrayLength = array.Length;
+ if ((uint)start > (uint)arrayLength)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ _length = arrayLength - start;
+ _pinnable = Unsafe.As>(array);
+ _byteOffset = SpanHelpers.PerTypeValues.ArrayAdjustment.Add(start);
+ }
+
+ ///
+ /// Creates a new span over the portion of the target array beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
+ ///
+ /// The target array.
+ /// The index at which to begin the span.
+ /// The number of items in the span.
+ /// Thrown when is a null
+ /// reference (Nothing in Visual Basic).
+ /// Thrown when is covariant and array's type is not exactly T[].
+ ///
+ /// Thrown when the specified or end index is not in the range (<0 or >=Length).
+ ///
+ [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_ArrayTypeMustBeExactMatch(typeof(T));
+ if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ _length = length;
+ _pinnable = Unsafe.As>(array);
+ _byteOffset = SpanHelpers.PerTypeValues.ArrayAdjustment.Add(start);
+ }
+
+ ///
+ /// 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.
+ ///
+ /// An unmanaged pointer to memory.
+ /// The number of elements the memory contains.
+ ///
+ /// Thrown when is reference type or contains pointers and hence cannot be stored in unmanaged memory.
+ ///
+ ///
+ /// Thrown when the specified is negative.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe Span(void* pointer, int length)
+ {
+ if (!SpanHelpers.IsReferenceFree())
+ ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
+ if (length < 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ _length = length;
+ _pinnable = null;
+ _byteOffset = new IntPtr(pointer);
+ }
+
+ ///
+ /// 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
+ /// "length" is not checked, nor is the fact that "rawPointer" actually lies within the object.
+ ///
+ /// The managed object that contains the data to span over.
+ /// A reference to data within that object.
+ /// The number of elements the memory contains.
+ ///
+ /// Thrown when the specified object is null.
+ ///
+ ///
+ /// Thrown when the specified is negative.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span DangerousCreate(object obj, ref T objectData, int length)
+ {
+ if (obj == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj);
+ if (length < 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
+
+ Pinnable pinnable = Unsafe.As>(obj);
+ IntPtr byteOffset = Unsafe.ByteOffset(ref pinnable.Data, ref objectData);
+ return new Span(pinnable, byteOffset, length);
+ }
+
+ // Constructor for internal use only.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Span(Pinnable pinnable, IntPtr byteOffset, int length)
+ {
+ Debug.Assert(length >= 0);
+
+ _length = length;
+ _pinnable = pinnable;
+ _byteOffset = byteOffset;
+ }
+
+ ///
+ /// The number of items in the span.
+ ///
+ public int Length => _length;
+
+ ///
+ /// Returns true if Length is 0.
+ ///
+ public bool IsEmpty => _length == 0;
+
+ ///
+ /// Returns a reference to specified element of the Span.
+ ///
+ ///
+ ///
+ ///
+ /// Thrown when index less than 0 or index greater than or equal to Length
+ ///
+
+ // TODO: https://github.com/dotnet/corefx/issues/13681
+ // Until we get over the hurdle of C# 7 tooling, this indexer will return "T" and have a setter rather than a "ref T". (The doc comments
+ // continue to reflect the original intent of returning "ref T")
+ public T this[int index]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ if ((uint)index >= ((uint)_length))
+ ThrowHelper.ThrowIndexOutOfRangeException();
+
+ if (_pinnable == null)
+ unsafe { return Unsafe.Add(ref Unsafe.AsRef(_byteOffset.ToPointer()), index); }
+ else
+ return Unsafe.Add(ref Unsafe.AddByteOffset(ref _pinnable.Data, _byteOffset), index);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set
+ {
+ if ((uint) index >= ((uint) _length))
+ ThrowHelper.ThrowIndexOutOfRangeException();
+
+ if (_pinnable == null)
+ unsafe { Unsafe.Add(ref Unsafe.AsRef(_byteOffset.ToPointer()), index) = value; }
+ else
+ Unsafe.Add(ref Unsafe.AddByteOffset(ref _pinnable.Data, _byteOffset), index) = value;
+ }
+ }
+
+ ///
+ /// Returns a reference to specified element of the Span.
+ ///
+ ///
+ ///
+ ///
+ /// Thrown when index less than 0 or index greater than or equal to Length
+ ///
+
+ // TODO: https://github.com/dotnet/corefx/issues/13681
+ // Until we get over the hurdle of C# 7 tooling, this temporary method will simulate the intended "ref T" indexer for those
+ // who need bypass the workaround for performance.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ref T GetItem(int index)
+ {
+ if ((uint)index >= ((uint)_length))
+ ThrowHelper.ThrowIndexOutOfRangeException();
+
+ if (_pinnable == null)
+ unsafe { return ref Unsafe.Add(ref Unsafe.AsRef(_byteOffset.ToPointer()), index); }
+ else
+ return ref Unsafe.Add(ref Unsafe.AddByteOffset(ref _pinnable.Data, _byteOffset), index);
+ }
+
+ ///
+ /// 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.
+ ///
+ /// The span to copy items into.
+ ///
+ /// Thrown when the destination Span is shorter than the source Span.
+ ///
+ ///
+ public void CopyTo(Span destination)
+ {
+ if (!TryCopyTo(destination))
+ ThrowHelper.ThrowArgumentException_DestinationTooShort();
+ }
+
+
+ ///
+ /// 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.
+ ///
+ /// If the destination span is shorter than the source span, this method
+ /// return false and no data is written to the destination.
+ ///
+ /// The span to copy items into.
+ public bool TryCopyTo(Span destination)
+ {
+ if ((uint)_length > (uint)destination._length)
+ return false;
+
+ // TODO: This is a tide-over implementation as we plan to add a overlap-safe cpblk-based api to Unsafe. (https://github.com/dotnet/corefx/issues/13427)
+ unsafe
+ {
+ ref T src = ref DangerousGetPinnableReference();
+ ref T dst = ref destination.DangerousGetPinnableReference();
+ IntPtr srcMinusDst = Unsafe.ByteOffset(ref dst, ref src);
+ int length = _length;
+
+ bool srcGreaterThanDst = (sizeof(IntPtr) == sizeof(int)) ? srcMinusDst.ToInt32() >= 0 : srcMinusDst.ToInt64() >= 0;
+ if (srcGreaterThanDst)
+ {
+ // Source address greater than or equal to destination address. Can do normal copy.
+ for (int i = 0; i < length; i++)
+ {
+ Unsafe.Add(ref dst, i) = Unsafe.Add(ref src, i);
+ }
+ }
+ else
+ {
+ // Source address less than destination address. Must do backward copy.
+ int i = length;
+ while (i-- != 0)
+ {
+ Unsafe.Add(ref dst, i) = Unsafe.Add(ref src, i);
+ }
+ }
+ return true;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ public static bool operator ==(Span left, Span right)
+ {
+ return left._length == right._length && Unsafe.AreSame(ref left.DangerousGetPinnableReference(), ref right.DangerousGetPinnableReference());
+ }
+
+ ///
+ /// 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.
+ ///
+ public static bool operator !=(Span left, Span right) => !(left == right);
+
+ ///
+ /// This method is not supported as spans cannot be boxed. To compare two spans, use operator==.
+ ///
+ /// Always thrown by this method.
+ ///
+ ///
+ [Obsolete("Equals() on Span will always throw an exception. Use == instead.")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool Equals(object obj)
+ {
+ throw new NotSupportedException(SR.CannotCallEqualsOnSpan);
+ }
+
+ ///
+ /// This method is not supported as spans cannot be boxed.
+ ///
+ /// Always thrown by this method.
+ ///
+ ///
+ [Obsolete("GetHashCode() on Span will always throw an exception.")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override int GetHashCode()
+ {
+ throw new NotSupportedException(SR.CannotCallGetHashCodeOnSpan);
+ }
+
+ ///
+ /// Defines an implicit conversion of an array to a
+ ///
+ public static implicit operator Span(T[] array) => new Span(array);
+
+ ///
+ /// Defines an implicit conversion of a to a
+ ///
+ public static implicit operator Span(ArraySegment arraySegment) => new Span(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
+
+ ///
+ /// Forms a slice out of the given span, beginning at 'start'.
+ ///
+ /// The index at which to begin this slice.
+ ///
+ /// Thrown when the specified index is not in range (<0 or >=Length).
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span Slice(int start)
+ {
+ if ((uint)start > (uint)_length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ IntPtr newOffset = _byteOffset.Add(start);
+ int length = _length - start;
+ return new Span(_pinnable, newOffset, length);
+ }
+
+ ///
+ /// Forms a slice out of the given span, beginning at 'start', of given length
+ ///
+ /// The index at which to begin this slice.
+ /// The desired length for the slice (exclusive).
+ ///
+ /// Thrown when the specified or end index is not in range (<0 or >=Length).
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span Slice(int start, int length)
+ {
+ if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ IntPtr newOffset = _byteOffset.Add(start);
+ return new Span(_pinnable, newOffset, length);
+ }
+
+ ///
+ /// 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.
+ ///
+ public T[] ToArray()
+ {
+ if (_length == 0)
+ return SpanHelpers.PerTypeValues.EmptyArray;
+
+ T[] result = new T[_length];
+ CopyTo(result);
+ return result;
+ }
+
+ ///
+ /// Returns a 0-length span whose base is the null pointer.
+ ///
+ public static readonly Span Empty = default(Span);
+
+ ///
+ /// 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.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ref T DangerousGetPinnableReference()
+ {
+ if (_pinnable == null)
+ unsafe { return ref Unsafe.AsRef(_byteOffset.ToPointer()); }
+ else
+ return ref Unsafe.AddByteOffset(ref _pinnable.Data, _byteOffset);
+ }
+
+ //
+ // If the Span was constructed from an object,
+ //
+ // _pinnable = that object (unsafe-casted to a Pinnable)
+ // _byteOffset = offset in bytes from "ref _pinnable.Data" to "ref span[0]"
+ //
+ // If the Span was constructed from a native pointer,
+ //
+ // _pinnable = null
+ // _byteOffset = the pointer
+ //
+ private readonly Pinnable _pinnable;
+ private readonly IntPtr _byteOffset;
+ private readonly int _length;
+ }
+}
diff --git a/src/System.Memory/src/System/SpanHelpers.cs b/src/System.Memory/src/System/SpanHelpers.cs
new file mode 100644
index 000000000000..fc9c5a28cb4a
--- /dev/null
+++ b/src/System.Memory/src/System/SpanHelpers.cs
@@ -0,0 +1,132 @@
+// 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.Reflection;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+ internal static class SpanHelpers
+ {
+ ///
+ /// Computes "start + index * sizeof(T)", using the unsigned IntPtr-sized multiplication for 32 and 64 bits.
+ ///
+ /// Assumptions:
+ /// Start and index are non-negative, and already pre-validated to be within the valid range of their containing Span.
+ ///
+ /// If the byte length (Span.Length * sizeof(T)) does an unsigned overflow (i.e. the buffer wraps or is too big to fit within the address space),
+ /// the behavior is undefined.
+ ///
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static IntPtr Add(this IntPtr start, int index)
+ {
+ Debug.Assert(start.ToInt64() >= 0);
+ Debug.Assert(index >= 0);
+
+ unsafe
+ {
+ if (sizeof(IntPtr) == sizeof(int))
+ {
+ // 32-bit path.
+ uint byteLength = (uint)index * (uint)Unsafe.SizeOf();
+ return (IntPtr)(((byte*)start) + byteLength);
+ }
+ else
+ {
+ // 64-bit path.
+ ulong byteLength = (ulong)index * (ulong)Unsafe.SizeOf();
+ return (IntPtr)(((byte*)start) + byteLength);
+ }
+ }
+ }
+
+ ///
+ /// Determine if a type is eligible for storage in unmanaged memory. TODO: To be replaced by a ContainsReference() api.
+ ///
+ public static bool IsReferenceFree() => PerTypeValues.IsReferenceFree;
+
+ private static bool IsReferenceFreeCore()
+ {
+ // Under the JIT, these become constant-folded.
+ if (typeof(T) == typeof(byte))
+ return true;
+ if (typeof(T) == typeof(sbyte))
+ return true;
+ if (typeof(T) == typeof(bool))
+ return true;
+ if (typeof(T) == typeof(char))
+ return true;
+ if (typeof(T) == typeof(short))
+ return true;
+ if (typeof(T) == typeof(ushort))
+ return true;
+ if (typeof(T) == typeof(int))
+ return true;
+ if (typeof(T) == typeof(uint))
+ return true;
+ if (typeof(T) == typeof(long))
+ return true;
+ if (typeof(T) == typeof(ulong))
+ return true;
+ if (typeof(T) == typeof(IntPtr))
+ return true;
+ if (typeof(T) == typeof(UIntPtr))
+ return true;
+
+ return IsReferenceFreeCoreSlow(typeof(T));
+ }
+
+ private static bool IsReferenceFreeCoreSlow(Type type)
+ {
+ if (type.GetTypeInfo().IsPrimitive) // This is hopefully the common case. All types that return true for this are value types w/out embedded references.
+ return true;
+
+ if (!type.GetTypeInfo().IsValueType)
+ return false;
+
+ // If type is a Nullable<> of something, unwrap it first.
+ Type underlyingNullable = Nullable.GetUnderlyingType(type);
+ if (underlyingNullable != null)
+ type = underlyingNullable;
+
+ if (type.GetTypeInfo().IsEnum)
+ return true;
+
+ foreach (FieldInfo field in type.GetTypeInfo().DeclaredFields)
+ {
+ if (field.IsStatic)
+ continue;
+ if (!IsReferenceFreeCoreSlow(field.FieldType))
+ return false;
+ }
+ return true;
+ }
+
+ public static class PerTypeValues
+ {
+ //
+ // Latch to ensure that excruciatingly expensive validation check for constructing a Span around a raw pointer is done
+ // only once per type (unless of course, the validation fails.)
+ //
+ // false == not yet computed or found to be not reference free.
+ // true == confirmed reference free
+ //
+ public static readonly bool IsReferenceFree = IsReferenceFreeCore();
+
+ public static readonly T[] EmptyArray = new T[0];
+
+ public static readonly IntPtr ArrayAdjustment = MeasureArrayAdjustment();
+
+ // Array header sizes are a runtime implementation detail and aren't the same across all runtimes. (The CLR made a tweak after 4.5, and Mono has an extra Bounds pointer.)
+ private static IntPtr MeasureArrayAdjustment()
+ {
+ T[] sampleArray = new T[1];
+ return Unsafe.ByteOffset(ref Unsafe.As>(sampleArray).Data, ref sampleArray[0]);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/src/System/ThrowHelper.cs b/src/System.Memory/src/System/ThrowHelper.cs
new file mode 100644
index 000000000000..c44556f158e0
--- /dev/null
+++ b/src/System.Memory/src/System/ThrowHelper.cs
@@ -0,0 +1,58 @@
+// 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;
+
+namespace System
+{
+ //
+ // This pattern of easily inlinable "void Throw" routines that stack on top of NoInlining factory methods
+ // is a compromise between older JITs and newer JITs (RyuJIT in Core CLR 1.1.0+ and desktop CLR in 4.6.3+).
+ // This package is explictly targeted at older JITs as newer runtimes expect to implement Span intrinsically for
+ // best performance.
+ //
+ // The aim of this pattern is three-fold
+ // 1. Extracting the throw makes the method preforming the throw in a conditional branch smaller and more inlinable
+ // 2. Extracting the throw from generic method to non-generic method reduces the repeated codegen size for value types
+ // 3a. Newer JITs will not inline the methods that only throw and also recognise them, move the call to cold section
+ // and not add stack prep and unwind before calling https://github.com/dotnet/coreclr/pull/6103
+ // 3b. Older JITs will inline the throw itself and move to cold section; but not inline the non-inlinable exception
+ // factory methods - still maintaining advantages 1 & 2
+ //
+
+ internal static class ThrowHelper
+ {
+ internal static void ThrowArgumentNullException(ExceptionArgument argument) { throw CreateArgumentNullException(argument); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateArgumentNullException(ExceptionArgument argument) { return new ArgumentNullException(argument.ToString()); }
+
+ internal static void ThrowArrayTypeMismatchException_ArrayTypeMustBeExactMatch(Type type) { throw CreateArrayTypeMismatchException_ArrayTypeMustBeExactMatch(type); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateArrayTypeMismatchException_ArrayTypeMustBeExactMatch(Type type) { return new ArrayTypeMismatchException(SR.Format(SR.ArrayTypeMustBeExactMatch, type)); }
+
+ internal static void ThrowArgumentException_InvalidTypeWithPointersNotSupported(Type type) { throw CreateArgumentException_InvalidTypeWithPointersNotSupported(type); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateArgumentException_InvalidTypeWithPointersNotSupported(Type type) { return new ArgumentException(SR.Format(SR.Argument_InvalidTypeWithPointersNotSupported, type)); }
+
+ internal static void ThrowArgumentException_DestinationTooShort() { throw CreateArgumentException_DestinationTooShort(); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateArgumentException_DestinationTooShort() { return new ArgumentException(SR.Argument_DestinationTooShort); }
+
+ internal static void ThrowIndexOutOfRangeException() { throw CreateIndexOutOfRangeException(); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateIndexOutOfRangeException() { return new IndexOutOfRangeException(); }
+
+ internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) { throw CreateArgumentOutOfRangeException(argument); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateArgumentOutOfRangeException(ExceptionArgument argument) { return new ArgumentOutOfRangeException(argument.ToString()); }
+ }
+
+ internal enum ExceptionArgument
+ {
+ array,
+ length,
+ start,
+ obj,
+ }
+}
diff --git a/src/System.Memory/src/project.json b/src/System.Memory/src/project.json
new file mode 100644
index 000000000000..e4874791d63d
--- /dev/null
+++ b/src/System.Memory/src/project.json
@@ -0,0 +1,13 @@
+{
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "System.Diagnostics.Debug": "4.0.11",
+ "System.Resources.ResourceManager": "4.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Reflection": "4.1.0",
+ "System.Runtime.CompilerServices.Unsafe": "4.4.0-beta-24715-02"
+ },
+ "frameworks": {
+ "netstandard1.0": {}
+ }
+}
diff --git a/src/System.Memory/tests/Span/CopyTo.cs b/src/System.Memory/tests/Span/CopyTo.cs
new file mode 100644
index 000000000000..9c895cbdf3b8
--- /dev/null
+++ b/src/System.Memory/tests/Span/CopyTo.cs
@@ -0,0 +1,87 @@
+// 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 Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class SpanTests
+ {
+ [Fact]
+ public static void TryCopyTo()
+ {
+ int[] src = { 1, 2, 3 };
+ int[] dst = { 99, 100, 101 };
+
+ Span srcSpan = new Span(src);
+ bool success = srcSpan.TryCopyTo(dst);
+ Assert.True(success);
+ Assert.Equal(src, dst);
+ }
+
+ [Fact]
+ public static void TryCopyToLonger()
+ {
+ int[] src = { 1, 2, 3 };
+ int[] dst = { 99, 100, 101, 102 };
+
+ Span srcSpan = new Span(src);
+ bool success = srcSpan.TryCopyTo(dst);
+ Assert.True(success);
+ int[] expected = { 1, 2, 3, 102 };
+ Assert.Equal(expected, dst);
+ }
+
+ [Fact]
+ public static void TryCopyToShorter()
+ {
+ int[] src = { 1, 2, 3 };
+ int[] dst = { 99, 100 };
+
+ Span srcSpan = new Span(src);
+ bool success = srcSpan.TryCopyTo(dst);
+ Assert.False(success);
+ int[] expected = { 99, 100 };
+ Assert.Equal(expected, dst); // TryCopyTo() checks for sufficient space before doing any copying.
+ }
+
+ [Fact]
+ public static void CopyToShorter()
+ {
+ int[] src = { 1, 2, 3 };
+ int[] dst = { 99, 100 };
+
+ Span srcSpan = new Span(src);
+ AssertThrows(srcSpan, (_srcSpan) => _srcSpan.CopyTo(dst));
+ int[] expected = { 99, 100 };
+ Assert.Equal(expected, dst); // CopyTo() checks for sufficient space before doing any copying.
+ }
+
+ [Fact]
+ public static void Overlapping1()
+ {
+ int[] a = { 90, 91, 92, 93, 94, 95, 96, 97 };
+
+ Span src = new Span(a, 1, 6);
+ Span dst = new Span(a, 2, 6);
+ src.CopyTo(dst);
+
+ int[] expected = { 90, 91, 91, 92, 93, 94, 95, 96 };
+ Assert.Equal(expected, a);
+ }
+
+ [Fact]
+ public static void Overlapping2()
+ {
+ int[] a = { 90, 91, 92, 93, 94, 95, 96, 97 };
+
+ Span src = new Span(a, 2, 6);
+ Span dst = new Span(a, 1, 6);
+ src.CopyTo(dst);
+
+ int[] expected = { 90, 92, 93, 94, 95, 96, 97, 97 };
+ Assert.Equal(expected, a);
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Span/CtorArray.cs b/src/System.Memory/tests/Span/CtorArray.cs
new file mode 100644
index 000000000000..625dc62b81ac
--- /dev/null
+++ b/src/System.Memory/tests/Span/CtorArray.cs
@@ -0,0 +1,121 @@
+// 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 Xunit;
+
+namespace System.SpanTests
+{
+ //
+ // Tests for Span.ctor(T[])
+ //
+ // These tests will also exercise the matching codepaths in Span.ctor(T[], int) and .ctor(T[], int, int). This makes it easier to ensure
+ // that these parallel tests stay consistent, and avoid excess repetition in the files devoted to those specific overloads.
+ //
+ public static partial class SpanTests
+ {
+ [Fact]
+ public static void CtorArray1()
+ {
+ int[] a = { 91, 92, -93, 94 };
+ Span span;
+
+ span = new Span(a);
+ span.Validate(91, 92, -93, 94);
+
+ span = new Span(a, 0);
+ span.Validate(91, 92, -93, 94);
+
+ span = new Span(a, 0, a.Length);
+ span.Validate(91, 92, -93, 94);
+ }
+
+ [Fact]
+ public static void CtorArray2()
+ {
+ long[] a = { 91, -92, 93, 94, -95 };
+ Span span;
+
+ span = new Span(a);
+ span.Validate(91, -92, 93, 94, -95);
+
+ span = new Span(a, 0);
+ span.Validate(91, -92, 93, 94, -95);
+
+ span = new Span(a, 0, a.Length);
+ span.Validate(91, -92, 93, 94, -95);
+ }
+
+ [Fact]
+ public static void CtorArray3()
+ {
+ object o1 = new object();
+ object o2 = new object();
+ object[] a = { o1, o2 };
+ Span