From 46e2da49084dd2770252636887cae0e836898111 Mon Sep 17 00:00:00 2001 From: Matt Warren Date: Wed, 30 Nov 2016 07:45:21 +0000 Subject: [PATCH] Adding missing ctor - 'public Span(T[] array, int start)' (dotnet/coreclr#8354) Commit migrated from https://github.com/dotnet/coreclr/commit/fb5f8d70e8b85e084af2cb52b70914b3428652a1 --- src/coreclr/src/mscorlib/model.xml | 2 + .../src/mscorlib/src/System/ReadOnlySpan.cs | 25 +++- src/coreclr/src/mscorlib/src/System/Span.cs | 30 ++++- .../src/CoreMangLib/system/span/BasicSpanTest.cs | 129 ++++++++++++++++++++- 4 files changed, 179 insertions(+), 7 deletions(-) diff --git a/src/coreclr/src/mscorlib/model.xml b/src/coreclr/src/mscorlib/model.xml index 71c8cab..c338e5c 100644 --- a/src/coreclr/src/mscorlib/model.xml +++ b/src/coreclr/src/mscorlib/model.xml @@ -12397,6 +12397,7 @@ + @@ -12415,6 +12416,7 @@ + diff --git a/src/coreclr/src/mscorlib/src/System/ReadOnlySpan.cs b/src/coreclr/src/mscorlib/src/System/ReadOnlySpan.cs index 4cdd14d..e94d353 100644 --- a/src/coreclr/src/mscorlib/src/System/ReadOnlySpan.cs +++ b/src/coreclr/src/mscorlib/src/System/ReadOnlySpan.cs @@ -38,6 +38,29 @@ namespace System /// /// 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 the specified is not in the range (<0 or >&eq;Length). + /// + public ReadOnlySpan(T[] array, int start) + { + if (array == null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); + if ((uint)start > (uint)array.Length) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead + _rawPointer = (IntPtr)Unsafe.AsPointer(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start)); + _length = array.Length - 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. @@ -46,7 +69,7 @@ namespace System /// Thrown when is a null /// reference (Nothing in Visual Basic). /// - /// Thrown when the specified or end index is not in range (<0 or >&eq;Length). + /// Thrown when the specified or end index is not in the range (<0 or >&eq;Length). /// public ReadOnlySpan(T[] array, int start, int length) { diff --git a/src/coreclr/src/mscorlib/src/System/Span.cs b/src/coreclr/src/mscorlib/src/System/Span.cs index 64764ed..2eff6ae 100644 --- a/src/coreclr/src/mscorlib/src/System/Span.cs +++ b/src/coreclr/src/mscorlib/src/System/Span.cs @@ -43,6 +43,34 @@ namespace System /// /// 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. + /// + /// Thrown when the specified is not in the range (<0 or >=Length). + /// + public Span(T[] array, int start) + { + if (array == null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); + if (default(T) == null) { // Arrays of valuetypes are never covariant + if (array.GetType() != typeof(T[])) + ThrowHelper.ThrowArrayTypeMismatchException(); + } + if ((uint)start > (uint)array.Length) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead + _rawPointer = (IntPtr)Unsafe.AsPointer(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start)); + _length = array.Length - 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. @@ -52,7 +80,7 @@ namespace System /// reference (Nothing in Visual Basic). /// Thrown when is covariant. /// - /// Thrown when the specified or end index is not in range (<0 or >&eq;Length). + /// Thrown when the specified or end index is not in the range (<0 or >=Length). /// public Span(T[] array, int start, int length) { diff --git a/src/coreclr/tests/src/CoreMangLib/system/span/BasicSpanTest.cs b/src/coreclr/tests/src/CoreMangLib/system/span/BasicSpanTest.cs index 7b0be90..18ec6f8 100644 --- a/src/coreclr/tests/src/CoreMangLib/system/span/BasicSpanTest.cs +++ b/src/coreclr/tests/src/CoreMangLib/system/span/BasicSpanTest.cs @@ -41,8 +41,11 @@ class My int failedTestsCount = 0; Test(CanAccessItemsViaIndexer, "CanAccessItemsViaIndexer", ref failedTestsCount); + Test(CanAccessItemsViaIndexerStartCtor, "CanAccessItemsViaIndexerStartCtor", ref failedTestsCount); + Test(CanAccessItemsViaIndexerStartLengthCtor, "CanAccessItemsViaIndexerStartLengthCtor", ref failedTestsCount); - Test(TestBoundaryEmptySpan, "TestBoundaryEmptySpan", ref failedTestsCount); + Test(TestBoundaryEmptySpanStartCtor, "TestBoundaryEmptySpanStartCtor", ref failedTestsCount); + Test(TestBoundaryEmptySpanStartLengthCtor, "TestBoundaryEmptySpanStartLengthCtor", ref failedTestsCount); Test(ReferenceTypesAreSupported, "ReferenceTypesAreSupported", ref failedTestsCount); @@ -51,6 +54,9 @@ class My Test(MustNotMoveGcTypesToUnmanagedMemory, "MustNotMoveGcTypesToUnmanagedMemory", ref failedTestsCount); Test(TestArrayCoVariance, "TestArrayCoVariance", ref failedTestsCount); + Test(TestArrayCoVarianceStartCtor, "TestArrayCoVarianceStartCtor", ref failedTestsCount); + Test(TestArrayCoVarianceStartLengthCtor, "TestArrayCoVarianceStartLengthCtor", ref failedTestsCount); + Test(TestArrayCoVarianceReadOnly, "TestArrayCoVarianceReadOnly", ref failedTestsCount); Test(CanCopyValueTypesWithoutPointersToSlice, "CanCopyValueTypesWithoutPointersToSlice", ref failedTestsCount); @@ -74,9 +80,13 @@ class My Test(SourceTypeLargerThanTargetOneCorrectlyCalcsTargetsLength, "SourceTypeLargerThanTargetOneCorrectlyCalcsTargetsLength", ref failedTestsCount); Test(WhenSourceDoesntFitIntoTargetLengthIsZero, "WhenSourceDoesntFitIntoTargetLengthIsZero", ref failedTestsCount); Test(WhenSourceFitsIntoTargetOnceLengthIsOne, "WhenSourceFitsIntoTargetOnceLengthIsOne", ref failedTestsCount); - Test(WhenSourceTypeLargerThaTargetAndOverflowsInt32ThrowsException, "WhenSourceTypeLargerThaTargetAndOverflowsInt32ThrowsException", ref failedTestsCount); + Test(WhenSourceTypeLargerThanTargetAndOverflowsInt32ThrowsException, "WhenSourceTypeLargerThanTargetAndOverflowsInt32ThrowsException", ref failedTestsCount); Test(CanCreateSpanFromString, "CanCreateSpanFromString", ref failedTestsCount); + Test(WhenStartLargerThanLengthThrowsExceptionStartCtor, "WhenStartLargerThanLengthThrowsExceptionStartCtor", ref failedTestsCount); + Test(WhenStartLargerThanLengthThrowsExceptionStartLengthCtor, "WhenStartLargerThanLengthThrowsExceptionStartLengthCtor", ref failedTestsCount); + Test(WhenStartAndLengthLargerThanLengthThrowsExceptionStartLengthCtor, "WhenStartAndLengthLargerThanLengthThrowsExceptionStartLengthCtor", ref failedTestsCount); + Console.WriteLine(string.Format("{0} tests has failed", failedTestsCount)); Environment.Exit(failedTestsCount); } @@ -91,9 +101,31 @@ class My AssertTrue(Sum(subslice) == 5, "Failed to sum subslice"); } - static TestBoundaryEmptySpan() + static void CanAccessItemsViaIndexerStartCtor() + { + int[] a = new int[] { 1, 2, 3 }; + Span slice = new Span(a, start: 1); + AssertTrue(Sum(slice) == 5, "Failed to sum slice"); + } + + static void CanAccessItemsViaIndexerStartLengthCtor() + { + int[] a = new int[] { 1, 2, 3 }; + Span slice = new Span(a, start: 1, length: 1); + AssertTrue(Sum(slice) == 2, "Failed to sum slice"); + } + + static void TestBoundaryEmptySpanStartCtor() { - int[] a = new byte[5]; + int[] a = new int[5]; + + Span slice = new Span(a, start: a.Length); + AssertEqual(slice.Length, 0); + } + + static void TestBoundaryEmptySpanStartLengthCtor() + { + int[] a = new int[5]; Span slice = new Span(a, a.Length, 0); AssertEqual(slice.Length, 0); @@ -165,6 +197,54 @@ class My } } + static void TestArrayCoVarianceStartCtor() + { + var array = new ReferenceType[1]; + var objArray = (object[])array; + try + { + new Span(objArray, start: 0); + AssertTrue(false, "Expected exception not thrown"); + } + catch (ArrayTypeMismatchException) + { + } + + var objEmptyArray = Array.Empty(); + try + { + new Span(objEmptyArray, start: 0); + AssertTrue(false, "Expected exception not thrown"); + } + catch (ArrayTypeMismatchException) + { + } + } + + static void TestArrayCoVarianceStartLengthCtor() + { + var array = new ReferenceType[1]; + var objArray = (object[])array; + try + { + new Span(objArray, start: 0, length: 1); + AssertTrue(false, "Expected exception not thrown"); + } + catch (ArrayTypeMismatchException) + { + } + + var objEmptyArray = Array.Empty(); + try + { + new Span(objEmptyArray, start: 0, length: 1); + AssertTrue(false, "Expected exception not thrown"); + } + catch (ArrayTypeMismatchException) + { + } + } + static void TestArrayCoVarianceReadOnly() { var array = new ReferenceType[1]; @@ -603,7 +683,7 @@ class My } } - static void WhenSourceTypeLargerThaTargetAndOverflowsInt32ThrowsException() + static void WhenSourceTypeLargerThanTargetAndOverflowsInt32ThrowsException() { unsafe { @@ -637,6 +717,45 @@ class My AssertEqualContent(secondHalfOfString, spanFromSecondHalf); } + static void WhenStartLargerThanLengthThrowsExceptionStartCtor() + { + try + { + var data = new byte[10]; + var slice = new Span(data, start: 11); + AssertTrue(false, "Expected exception for Argument Out of Range not thrown"); + } + catch (System.ArgumentOutOfRangeException) + { + } + } + + static void WhenStartLargerThanLengthThrowsExceptionStartLengthCtor() + { + try + { + var data = new byte[10]; + var slice = new Span(data, start: 11, length: 0); + AssertTrue(false, "Expected exception for Argument Out of Range not thrown"); + } + catch (System.ArgumentOutOfRangeException) + { + } + } + + static void WhenStartAndLengthLargerThanLengthThrowsExceptionStartLengthCtor() + { + try + { + var data = new byte[10]; + var slice = new Span(data, start: 1, length: 10); + AssertTrue(false, "Expected exception for Argument Out of Range not thrown"); + } + catch (System.ArgumentOutOfRangeException) + { + } + } + static void Test(Action test, string testName, ref int failedTestsCount) { try -- 2.7.4