From c46858e6ed5b26382fa6883d9aad6cc365800896 Mon Sep 17 00:00:00 2001 From: Matt Warren Date: Mon, 12 Dec 2016 17:30:58 +0000 Subject: [PATCH] Span api update (dotnet/coreclr#8583) * Changing method/property order to match CoreFX impl To make diffing the files easier * Added other missing methods to match CoreFX impl Added: - public void CopyTo(Span destination) - public static bool operator ==(Span left, Span right) - public static bool operator !=(Span left, Span right) - public override bool Equals(object obj) - public override int GetHashCode() Also removed 'public void Set(ReadOnlySpan values)' and it's no longer part of the Span public API, see https://github.com/dotnet/apireviews/tree/master/2016/11-04-SpanOfT#spantset Commit migrated from https://github.com/dotnet/coreclr/commit/98798b78e2e3284409289c7253bac7b999c0ad88 --- src/coreclr/src/mscorlib/model.xml | 6 +- .../src/mscorlib/src/System.Private.CoreLib.txt | 5 + src/coreclr/src/mscorlib/src/System/Span.cs | 182 ++++++++++++--------- src/coreclr/src/mscorlib/src/System/ThrowHelper.cs | 12 ++ 4 files changed, 130 insertions(+), 75 deletions(-) diff --git a/src/coreclr/src/mscorlib/model.xml b/src/coreclr/src/mscorlib/model.xml index c221d6c..64901a2 100644 --- a/src/coreclr/src/mscorlib/model.xml +++ b/src/coreclr/src/mscorlib/model.xml @@ -12422,6 +12422,8 @@ + + @@ -12431,8 +12433,10 @@ + + + - diff --git a/src/coreclr/src/mscorlib/src/System.Private.CoreLib.txt b/src/coreclr/src/mscorlib/src/System.Private.CoreLib.txt index ee1a962..cf17dae 100644 --- a/src/coreclr/src/mscorlib/src/System.Private.CoreLib.txt +++ b/src/coreclr/src/mscorlib/src/System.Private.CoreLib.txt @@ -592,6 +592,7 @@ Argument_NativeOverlappedAlreadyFree = 'overlapped' has already been freed. Argument_AlreadyBoundOrSyncHandle = 'handle' has already been bound to the thread pool, or was not opened for asynchronous I/O. #if FEATURE_SPAN_OF_T Argument_InvalidTypeWithPointersNotSupported = Cannot use type '{0}'. Only value types without pointers or references are supported. +Argument_DestinationTooShort = Destination is too short. #endif // FEATURE_SPAN_OF_T ; @@ -1431,6 +1432,10 @@ NotSupported_WindowsPhone = {0} is not supported. NotSupported_AssemblyLoadCodeBase = Assembly.Load with a Codebase is not supported. NotSupported_AssemblyLoadFromHash = Assembly.LoadFrom with hashValue is not supported. #endif +#if FEATURE_SPAN_OF_T +NotSupported_CannotCallEqualsOnSpan = Equals() on Span and ReadOnlySpan is not supported. Use operator== instead. +NotSupported_CannotCallGetHashCodeOnSpan = GetHashCode() on Span and ReadOnlySpan is not supported. +#endif // FEATURE_SPAN_OF_T ; TypeLoadException TypeLoad_ResolveType = Could not resolve type '{0}'. diff --git a/src/coreclr/src/mscorlib/src/System/Span.cs b/src/coreclr/src/mscorlib/src/System/Span.cs index 21785cd..f1d57d3 100644 --- a/src/coreclr/src/mscorlib/src/System/Span.cs +++ b/src/coreclr/src/mscorlib/src/System/Span.cs @@ -6,6 +6,8 @@ using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; +#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' + namespace System { /// @@ -26,7 +28,7 @@ namespace System /// The target array. /// Thrown when is a null /// reference (Nothing in Visual Basic). - /// Thrown when is covariant. + /// Thrown when is covariant and array's type is not exactly T[]. public Span(T[] array) { if (array == null) @@ -48,7 +50,7 @@ namespace System /// The index at which to begin the span. /// Thrown when is a null /// reference (Nothing in Visual Basic). - /// Thrown when is covariant. + /// Thrown when is covariant and array's type is not exactly T[]. /// /// Thrown when the specified is not in the range (<0 or >=Length). /// @@ -76,7 +78,7 @@ namespace System /// The number of items in the span. /// Thrown when is a null /// reference (Nothing in Visual Basic). - /// Thrown when is covariant. + /// 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). /// @@ -101,7 +103,7 @@ namespace System /// 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. + /// 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. @@ -140,44 +142,14 @@ namespace System } /// - /// Defines an implicit conversion of an array to a - /// - public static implicit operator Span(T[] array) - { - return new Span(array); - } - - /// - /// Defines an implicit conversion of a to a - /// - public static implicit operator Span(ArraySegment arraySegment) - { - return new Span(arraySegment.Array, arraySegment.Offset, arraySegment.Count); - } - - /// /// Gets the number of elements contained in the /// - public int Length - { - get { return _length; } - } - - /// - /// Returns an empty - /// - public static Span Empty - { - get { return default(Span); } - } + public int Length => _length; /// /// Returns whether the is empty. /// - public bool IsEmpty - { - get { return _length == 0; } - } + public bool IsEmpty => _length == 0; /// /// Fetches the element at the specified index. @@ -204,21 +176,98 @@ namespace System } /// - /// Copies the contents of this span into a new array. This heap - /// allocates, so should generally be avoided, however is sometimes - /// necessary to bridge the gap with APIs written in terms of arrays. + /// 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. /// - public T[] ToArray() + /// The span to copy items into. + /// + /// Thrown when the destination Span is shorter than the source Span. + /// + public void CopyTo(Span destination) { - if (_length == 0) - return Array.Empty(); + if (!TryCopyTo(destination)) + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } - var destination = new T[_length]; - SpanHelper.CopyTo(ref JitHelpers.GetArrayData(destination), ref DangerousGetPinnableReference(), _length); - return destination; + /// + /// 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. + /// If the destination span is shorter than the source span, this method + /// return false and no data is written to the destination. + public bool TryCopyTo(Span destination) + { + if ((uint)_length > (uint)destination.Length) + return false; + + SpanHelper.CopyTo(ref destination.DangerousGetPinnableReference(), ref DangerousGetPinnableReference(), _length); + 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) => left.Equals(right); + + /// + /// 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.Equals(right); + + /// + /// Checks to see if two spans point at the same memory. Note that + /// this does *not* check to see if the *contents* are equal. + /// + public bool Equals(Span other) + { + return (_length == other.Length) && + (_length == 0 || Unsafe.AreSame(ref DangerousGetPinnableReference(), ref other.DangerousGetPinnableReference())); + } + + /// + /// 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.")] + public override bool Equals(object obj) + { + ThrowHelper.ThrowNotSupportedException_CannotCallEqualsOnSpan(); + // Prevent compiler error CS0161: 'Span.Equals(object)': not all code paths return a value + return default(bool); + } + + /// + /// This method is not supported as spans cannot be boxed. + /// + /// Always thrown by this method. + /// + /// + [Obsolete("GetHashCode() on Span will always throw an exception.")] + public override int GetHashCode() + { + ThrowHelper.ThrowNotSupportedException_CannotCallGetHashCodeOnSpan(); + // Prevent compiler error CS0161: 'Span.GetHashCode()': not all code paths return a value + return default(int); + } + + /// + /// 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. @@ -238,7 +287,7 @@ namespace System /// Forms a slice out of the given span, beginning at 'start', of given length /// /// The index at which to begin this slice. - /// The index at which to end this slice (exclusive). + /// The desired length for the slice (exclusive). /// /// Thrown when the specified or end index is not in range (<0 or >&eq;Length). /// @@ -252,39 +301,24 @@ namespace System } /// - /// Checks to see if two spans point at the same memory. Note that - /// this does *not* check to see if the *contents* are equal. - /// - public bool Equals(Span other) - { - return (_length == other.Length) && - (_length == 0 || Unsafe.AreSame(ref DangerousGetPinnableReference(), ref other.DangerousGetPinnableReference())); - } - - /// - /// Copies the contents of this span into destination span. The destination - /// must be at least as big as the source, and may be bigger. + /// 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. /// - /// The span to copy items into. - public bool TryCopyTo(Span destination) + public T[] ToArray() { - if ((uint)_length > (uint)destination.Length) - return false; + if (_length == 0) + return Array.Empty(); - SpanHelper.CopyTo(ref destination.DangerousGetPinnableReference(), ref DangerousGetPinnableReference(), _length); - return true; + var destination = new T[_length]; + SpanHelper.CopyTo(ref JitHelpers.GetArrayData(destination), ref DangerousGetPinnableReference(), _length); + return destination; } - /// - /// Thrown when the specified 's Length is longer than source span's Length. - /// - public void Set(ReadOnlySpan values) - { - if ((uint)values.Length > (uint)_length) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - SpanHelper.CopyTo(ref DangerousGetPinnableReference(), ref values.DangerousGetPinnableReference(), values.Length); - } + // + /// Returns an empty + /// + public static Span Empty => default(Span); } public static class SpanExtensions diff --git a/src/coreclr/src/mscorlib/src/System/ThrowHelper.cs b/src/coreclr/src/mscorlib/src/System/ThrowHelper.cs index be91d7c..74a08cd 100644 --- a/src/coreclr/src/mscorlib/src/System/ThrowHelper.cs +++ b/src/coreclr/src/mscorlib/src/System/ThrowHelper.cs @@ -59,6 +59,18 @@ namespace System { internal static void ThrowArgumentOutOfRangeException() { throw new ArgumentOutOfRangeException(); } + + internal static void ThrowArgumentException_DestinationTooShort() { + throw new ArgumentException(Environment.GetResourceString("Argument_DestinationTooShort")); + } + + internal static void ThrowNotSupportedException_CannotCallEqualsOnSpan() { + throw new NotSupportedException(Environment.GetResourceString("NotSupported_CannotCallEqualsOnSpan")); + } + + internal static void ThrowNotSupportedException_CannotCallGetHashCodeOnSpan() { + throw new NotSupportedException(Environment.GetResourceString("NotSupported_CannotCallGetHashCodeOnSpan")); + } #endif internal static void ThrowArgumentOutOfRange_IndexException() { -- 2.7.4