From cec971b31bb12bfa0bc8ac2b81f03b62ea9027a8 Mon Sep 17 00:00:00 2001 From: ahsonkhan Date: Mon, 12 Dec 2016 18:05:33 -0800 Subject: [PATCH 1/4] Adding method implementations to fast span/readonlyspan Adding some missing method definitions. --- src/mscorlib/model.xml | 5 ++ src/mscorlib/src/System/ReadOnlySpan.cs | 67 +++++++++++++++++++++++++ src/mscorlib/src/System/Span.cs | 7 ++- 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/mscorlib/model.xml b/src/mscorlib/model.xml index 64901a2207c5..7904287bbd8f 100644 --- a/src/mscorlib/model.xml +++ b/src/mscorlib/model.xml @@ -12447,6 +12447,8 @@ + + @@ -12455,7 +12457,10 @@ + + + diff --git a/src/mscorlib/src/System/ReadOnlySpan.cs b/src/mscorlib/src/System/ReadOnlySpan.cs index 9235fcfa74dc..4b92cd312189 100644 --- a/src/mscorlib/src/System/ReadOnlySpan.cs +++ b/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 { /// @@ -30,6 +32,8 @@ public ReadOnlySpan(T[] array) { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); + if (default(T) == null && array.GetType() != typeof(T[])) + ThrowHelper.ThrowArrayTypeMismatchException(); _pointer = new ByReference(ref JitHelpers.GetArrayData(array)); _length = array.Length; @@ -50,6 +54,8 @@ public ReadOnlySpan(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(); @@ -73,6 +79,8 @@ public ReadOnlySpan(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(); @@ -124,6 +132,34 @@ 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); + } + /// /// Defines an implicit conversion of a to a /// @@ -247,6 +283,22 @@ public bool Equals(ReadOnlySpan other) (_length == 0 || Unsafe.AreSame(ref DangerousGetPinnableReference(), ref other.DangerousGetPinnableReference())); } + /// + /// 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 void CopyTo(Span destination) + { + if (!TryCopyTo(destination)) + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + /// /// Copies the contents of this span into destination span. The destination /// must be at least as big as the source, and may be bigger. @@ -260,6 +312,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/mscorlib/src/System/Span.cs b/src/mscorlib/src/System/Span.cs index f1d57d390b12..2fe7a0ac4bb5 100644 --- a/src/mscorlib/src/System/Span.cs +++ b/src/mscorlib/src/System/Span.cs @@ -211,13 +211,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); + public static bool operator !=(Span left, Span right) => !(left == right); /// /// Checks to see if two spans point at the same memory. Note that From 12ff4c1dea5358b3c1b0bec48d2fb96e4f362f49 Mon Sep 17 00:00:00 2001 From: ahsonkhan Date: Tue, 13 Dec 2016 13:56:59 -0800 Subject: [PATCH 2/4] Addressing PR comments Removed Equals(Span/ReadonlySpan) Removed type check in readonlyspan Added DangerousCreate methods --- src/mscorlib/model.xml | 4 ++-- src/mscorlib/src/System/ReadOnlySpan.cs | 26 ++++++++++--------------- src/mscorlib/src/System/Span.cs | 20 +++++++++---------- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/mscorlib/model.xml b/src/mscorlib/model.xml index 7904287bbd8f..e61c139cf1d7 100644 --- a/src/mscorlib/model.xml +++ b/src/mscorlib/model.xml @@ -12432,8 +12432,8 @@ - + @@ -12456,8 +12456,8 @@ - + diff --git a/src/mscorlib/src/System/ReadOnlySpan.cs b/src/mscorlib/src/System/ReadOnlySpan.cs index 4b92cd312189..067cc0ccab43 100644 --- a/src/mscorlib/src/System/ReadOnlySpan.cs +++ b/src/mscorlib/src/System/ReadOnlySpan.cs @@ -32,8 +32,6 @@ public ReadOnlySpan(T[] array) { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - if (default(T) == null && array.GetType() != typeof(T[])) - ThrowHelper.ThrowArrayTypeMismatchException(); _pointer = new ByReference(ref JitHelpers.GetArrayData(array)); _length = array.Length; @@ -54,8 +52,6 @@ public ReadOnlySpan(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(); @@ -79,8 +75,6 @@ public ReadOnlySpan(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(); @@ -160,6 +154,16 @@ public override int GetHashCode() 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. + public static ReadOnlySpan DangerousCreate(object obj, ref T objectData, int length) => new ReadOnlySpan(ref objectData, length); + /// /// Defines an implicit conversion of a to a /// @@ -273,16 +277,6 @@ public ReadOnlySpan Slice(int start, int length) return new ReadOnlySpan(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), 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. - /// - public bool Equals(ReadOnlySpan other) - { - return (_length == other.Length) && - (_length == 0 || Unsafe.AreSame(ref DangerousGetPinnableReference(), ref other.DangerousGetPinnableReference())); - } - /// /// 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 diff --git a/src/mscorlib/src/System/Span.cs b/src/mscorlib/src/System/Span.cs index 2fe7a0ac4bb5..c421fd0f4679 100644 --- a/src/mscorlib/src/System/Span.cs +++ b/src/mscorlib/src/System/Span.cs @@ -123,6 +123,16 @@ 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. + public static Span DangerousCreate(object obj, ref T objectData, int length) => new Span(ref objectData, length); + /// /// An internal helper for creating spans. /// @@ -222,16 +232,6 @@ public bool TryCopyTo(Span destination) /// public static bool operator !=(Span left, Span right) => !(left == 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==. /// From 20d6e9a0bbf494eb8e1378f0771e9f4630ca2d14 Mon Sep 17 00:00:00 2001 From: ahsonkhan Date: Tue, 13 Dec 2016 15:17:30 -0800 Subject: [PATCH 3/4] Adding object null and length checks for dangerouscreate --- src/mscorlib/src/System/ReadOnlySpan.cs | 16 +++++++++++++++- src/mscorlib/src/System/Span.cs | 17 ++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/mscorlib/src/System/ReadOnlySpan.cs b/src/mscorlib/src/System/ReadOnlySpan.cs index 067cc0ccab43..762a39b65183 100644 --- a/src/mscorlib/src/System/ReadOnlySpan.cs +++ b/src/mscorlib/src/System/ReadOnlySpan.cs @@ -162,7 +162,21 @@ public override int GetHashCode() /// The managed object that contains the data to span over. /// A reference to data within that object. /// The number of elements the memory contains. - public static ReadOnlySpan DangerousCreate(object obj, ref T objectData, int length) => new ReadOnlySpan(ref objectData, length); + /// + /// 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 diff --git a/src/mscorlib/src/System/Span.cs b/src/mscorlib/src/System/Span.cs index c421fd0f4679..46751e6f0c02 100644 --- a/src/mscorlib/src/System/Span.cs +++ b/src/mscorlib/src/System/Span.cs @@ -131,7 +131,22 @@ public unsafe Span(void* pointer, int length) /// The managed object that contains the data to span over. /// A reference to data within that object. /// The number of elements the memory contains. - public static Span DangerousCreate(object obj, ref T objectData, int length) => new Span(ref objectData, length); + /// + /// 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. From 366f808245a000baf35e713b7f036c04bdc7967a Mon Sep 17 00:00:00 2001 From: ahsonkhan Date: Tue, 13 Dec 2016 16:59:32 -0800 Subject: [PATCH 4/4] Adding missing implicit operator --- src/mscorlib/model.xml | 1 + src/mscorlib/src/System/Span.cs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/mscorlib/model.xml b/src/mscorlib/model.xml index a35c06cd2d15..afc6af1f4c7d 100644 --- a/src/mscorlib/model.xml +++ b/src/mscorlib/model.xml @@ -12424,6 +12424,7 @@ + diff --git a/src/mscorlib/src/System/Span.cs b/src/mscorlib/src/System/Span.cs index 46751e6f0c02..17d41116e0cd 100644 --- a/src/mscorlib/src/System/Span.cs +++ b/src/mscorlib/src/System/Span.cs @@ -285,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'. ///