diff --git a/src/coreclr/src/mscorlib/model.xml b/src/coreclr/src/mscorlib/model.xml index 104fc6e5ede392..afc6af1f4c7de8 100644 --- a/src/coreclr/src/mscorlib/model.xml +++ b/src/coreclr/src/mscorlib/model.xml @@ -12424,6 +12424,7 @@ + @@ -12434,8 +12435,8 @@ - + @@ -12449,6 +12450,8 @@ + + @@ -12456,8 +12459,11 @@ - + + + + diff --git a/src/coreclr/src/mscorlib/src/System/ReadOnlySpan.cs b/src/coreclr/src/mscorlib/src/System/ReadOnlySpan.cs index 9235fcfa74dca3..762a39b6518337 100644 --- a/src/coreclr/src/mscorlib/src/System/ReadOnlySpan.cs +++ b/src/coreclr/src/mscorlib/src/System/ReadOnlySpan.cs @@ -6,6 +6,8 @@ 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 { /// @@ -124,6 +126,58 @@ public ref T DangerousGetPinnableReference() return ref _pointer.Value; } + /// + /// 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); + } + + /// + /// Create a new read-only span over a portion of a regular managed object. This can be useful + /// if part of a managed object represents a "fixed array." This is dangerous because + /// "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. + /// + public static ReadOnlySpan DangerousCreate(object obj, ref T objectData, int length) + { + if (obj == null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj); + if (length < 0) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length); + + return new ReadOnlySpan(ref objectData, length); + } + /// /// Defines an implicit conversion of a to a /// @@ -238,13 +292,19 @@ public ReadOnlySpan Slice(int start, int length) } /// - /// Checks to see if two spans point at the same memory. Note that - /// this does *not* check to see if the *contents* are equal. + /// Copies the contents of this read-only span into destination span. If the source + /// and destinations overlap, this method behaves as if the original values in + /// a temporary location before the destination is overwritten. + /// + /// The span to copy items into. + /// + /// Thrown when the destination Span is shorter than the source Span. + /// /// - public bool Equals(ReadOnlySpan other) + public void CopyTo(Span destination) { - return (_length == other.Length) && - (_length == 0 || Unsafe.AreSame(ref DangerousGetPinnableReference(), ref other.DangerousGetPinnableReference())); + if (!TryCopyTo(destination)) + ThrowHelper.ThrowArgumentException_DestinationTooShort(); } /// @@ -260,6 +320,21 @@ public bool TryCopyTo(Span destination) 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 ==(ReadOnlySpan left, ReadOnlySpan 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 !=(ReadOnlySpan left, ReadOnlySpan right) => !(left == right); } public static class ReadOnlySpanExtensions diff --git a/src/coreclr/src/mscorlib/src/System/Span.cs b/src/coreclr/src/mscorlib/src/System/Span.cs index f1d57d390b127d..17d41116e0cd35 100644 --- a/src/coreclr/src/mscorlib/src/System/Span.cs +++ b/src/coreclr/src/mscorlib/src/System/Span.cs @@ -123,6 +123,31 @@ public unsafe Span(void* pointer, int length) _length = length; } + /// + /// 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. + /// + 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); + + return new Span(ref objectData, length); + } + + /// /// An internal helper for creating spans. /// @@ -211,23 +236,16 @@ public bool TryCopyTo(Span destination) /// 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); + 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.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())); - } + 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==. @@ -267,6 +285,11 @@ public override int GetHashCode() /// public static implicit operator Span(ArraySegment arraySegment) => new Span(arraySegment.Array, arraySegment.Offset, arraySegment.Count); + /// + /// Defines an implicit conversion of a to a + /// + public static implicit operator ReadOnlySpan(Span span) => new ReadOnlySpan(ref span.DangerousGetPinnableReference(), span._length); + /// /// Forms a slice out of the given span, beginning at 'start'. ///