Skip to content

Commit 7e2d8a8

Browse files
author
msftbot[bot]
authored
Fix [ReadOnly]Span2D<T>.TryGetSpan on legacy frameworks (#3948)
## Fixes #3947 <!-- Add the relevant issue number after the "#" mentioned above (for ex: Fixes #1234) which will automatically close the issue once the PR is merged. --> <!-- Add a brief overview here of the feature/bug & fix. --> ## PR Type What kind of change does this PR introduce? <!-- Please uncomment one or more that apply to this PR. --> - Bugfix <!-- - Feature --> <!-- - Code style update (formatting) --> <!-- - Refactoring (no functional changes, no api changes) --> <!-- - Build or CI related changes --> <!-- - Documentation content changes --> <!-- - Sample app changes --> <!-- - Other... Please describe: --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying, or link to a relevant issue. --> `[ReadOnly]Span2D<T>.TryGetSpan` throws an exception when wrapping a `T[]` instance on legacy frameworks. ## What is the new behavior? <!-- Describe how was this issue resolved or changed? --> `[ReadOnly]Span2D<T>.TryGetSpan` works correctly on legacy frameworks. ## PR Checklist Please check if your PR fulfills the following requirements: - [X] Tested code with current [supported SDKs](../readme.md#supported) - [ ] ~~Pull Request has been submitted to the documentation repository [instructions](..\contributing.md#docs). Link: <!-- docs PR link -->~~ - [ ] ~~Sample in sample app has been added / updated (for bug fixes / features)~~ - [ ] ~~Icon has been created (if new sample) following the [Thumbnail Style Guide and templates](https://github.com/windows-toolkit/WindowsCommunityToolkit-design-assets)~~ - [X] New major technical changes in the toolkit have or will be added to the [Wiki](https://github.com/windows-toolkit/WindowsCommunityToolkit/wiki) e.g. build changes, source generators, testing infrastructure, sample creation changes, etc... - [X] Tests for the changes have been added (for bug fixes / features) (if applicable) - [X] Header has been added to all new source files (run *build/UpdateHeaders.bat*) - [X] Contains **NO** breaking changes
2 parents 68888d2 + c326085 commit 7e2d8a8

File tree

4 files changed

+115
-6
lines changed

4 files changed

+115
-6
lines changed

Microsoft.Toolkit.HighPerformance/Memory/ReadOnlySpan2D{T}.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,10 @@ public bool TryGetSpan(out ReadOnlySpan<T> span)
906906
// Without Span<T> runtime support, we can only get a Span<T> from a T[] instance
907907
if (this.instance.GetType() == typeof(T[]))
908908
{
909-
span = Unsafe.As<T[]>(this.instance).AsSpan((int)this.offset, (int)Length);
909+
T[] array = Unsafe.As<T[]>(this.instance)!;
910+
int index = array.AsSpan().IndexOf(ref ObjectMarshal.DangerousGetObjectDataReferenceAt<T>(array, this.offset));
911+
912+
span = array.AsSpan(index, (int)Length);
910913

911914
return true;
912915
}

Microsoft.Toolkit.HighPerformance/Memory/Span2D{T}.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1062,7 +1062,10 @@ public bool TryGetSpan(out Span<T> span)
10621062
// Without Span<T> runtime support, we can only get a Span<T> from a T[] instance
10631063
if (this.Instance.GetType() == typeof(T[]))
10641064
{
1065-
span = Unsafe.As<T[]>(this.Instance).AsSpan((int)this.Offset, (int)Length);
1065+
T[] array = Unsafe.As<T[]>(this.Instance)!;
1066+
int index = array.AsSpan().IndexOf(ref ObjectMarshal.DangerousGetObjectDataReferenceAt<T>(array, this.Offset));
1067+
1068+
span = array.AsSpan(index, (int)Length);
10661069

10671070
return true;
10681071
}

UnitTests/UnitTests.HighPerformance.Shared/Memory/Test_ReadOnlySpan2D{T}.cs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,51 @@ ref Unsafe.AsRef(span[2]),
586586

587587
[TestCategory("ReadOnlySpan2DT")]
588588
[TestMethod]
589-
public void Test_ReadOnlySpan2DT_TryGetReadOnlySpan_1()
589+
public void Test_ReadOnlySpan2DT_TryGetSpan_From1DArray_1()
590+
{
591+
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
592+
593+
ReadOnlySpan2D<int> span2d = new ReadOnlySpan2D<int>(array, 3, 3);
594+
595+
bool success = span2d.TryGetSpan(out ReadOnlySpan<int> span);
596+
597+
Assert.IsTrue(success);
598+
Assert.AreEqual(span.Length, span2d.Length);
599+
Assert.IsTrue(Unsafe.AreSame(ref array[0], ref Unsafe.AsRef(in span[0])));
600+
}
601+
602+
[TestCategory("ReadOnlySpan2DT")]
603+
[TestMethod]
604+
public void Test_ReadOnlySpan2DT_TryGetSpan_From1DArray_2()
605+
{
606+
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
607+
608+
ReadOnlySpan2D<int> span2d = new ReadOnlySpan2D<int>(array, 3, 3).Slice(1, 0, 2, 3);
609+
610+
bool success = span2d.TryGetSpan(out ReadOnlySpan<int> span);
611+
612+
Assert.IsTrue(success);
613+
Assert.AreEqual(span.Length, span2d.Length);
614+
Assert.IsTrue(Unsafe.AreSame(ref array[3], ref Unsafe.AsRef(in span[0])));
615+
}
616+
617+
[TestCategory("ReadOnlySpan2DT")]
618+
[TestMethod]
619+
public void Test_ReadOnlySpan2DT_TryGetSpan_From1DArray_3()
620+
{
621+
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
622+
623+
ReadOnlySpan2D<int> span2d = new ReadOnlySpan2D<int>(array, 3, 3).Slice(0, 1, 3, 2);
624+
625+
bool success = span2d.TryGetSpan(out ReadOnlySpan<int> span);
626+
627+
Assert.IsFalse(success);
628+
Assert.AreEqual(span.Length, 0);
629+
}
630+
631+
[TestCategory("ReadOnlySpan2DT")]
632+
[TestMethod]
633+
public void Test_ReadOnlySpan2DT_TryGetReadOnlySpan_From2DArray_1()
590634
{
591635
int[,] array =
592636
{
@@ -610,7 +654,7 @@ public void Test_ReadOnlySpan2DT_TryGetReadOnlySpan_1()
610654

611655
[TestCategory("ReadOnlySpan2DT")]
612656
[TestMethod]
613-
public void Test_ReadOnlySpan2DT_TryGetReadOnlySpan_2()
657+
public void Test_ReadOnlySpan2DT_TryGetReadOnlySpan_From2DArray_2()
614658
{
615659
int[,] array =
616660
{

UnitTests/UnitTests.HighPerformance.Shared/Memory/Test_Span2D{T}.cs

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,66 @@ public void Test_Span2DT_GetRowSpan()
761761

762762
[TestCategory("Span2DT")]
763763
[TestMethod]
764-
public void Test_Span2DT_TryGetSpan_1()
764+
public void Test_Span2DT_TryGetSpan_From1DArray_1()
765+
{
766+
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
767+
768+
Span2D<int> span2d = new Span2D<int>(array, 3, 3);
769+
770+
bool success = span2d.TryGetSpan(out Span<int> span);
771+
772+
Assert.IsTrue(success);
773+
Assert.AreEqual(span.Length, span2d.Length);
774+
Assert.IsTrue(Unsafe.AreSame(ref array[0], ref span[0]));
775+
}
776+
777+
[TestCategory("Span2DT")]
778+
[TestMethod]
779+
public void Test_Span2DT_TryGetSpan_From1DArray_2()
780+
{
781+
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
782+
783+
Span2D<int> span2d = new Span2D<int>(array, 3, 3).Slice(1, 0, 2, 3);
784+
785+
bool success = span2d.TryGetSpan(out Span<int> span);
786+
787+
Assert.IsTrue(success);
788+
Assert.AreEqual(span.Length, span2d.Length);
789+
Assert.IsTrue(Unsafe.AreSame(ref array[3], ref span[0]));
790+
}
791+
792+
[TestCategory("Span2DT")]
793+
[TestMethod]
794+
public void Test_Span2DT_TryGetSpan_From1DArray_3()
795+
{
796+
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
797+
798+
Span2D<int> span2d = new Span2D<int>(array, 3, 3).Slice(0, 1, 3, 2);
799+
800+
bool success = span2d.TryGetSpan(out Span<int> span);
801+
802+
Assert.IsFalse(success);
803+
Assert.AreEqual(span.Length, 0);
804+
}
805+
806+
// See https://github.com/windows-toolkit/WindowsCommunityToolkit/issues/3947
807+
[TestCategory("Span2DT")]
808+
[TestMethod]
809+
public void Test_Span2DT_TryGetSpan_From1DArray_4()
810+
{
811+
int[] array = new int[128];
812+
Span2D<int> span2d = new Span2D<int>(array, 8, 16);
813+
814+
bool success = span2d.TryGetSpan(out Span<int> span);
815+
816+
Assert.IsTrue(success);
817+
Assert.AreEqual(span.Length, span2d.Length);
818+
Assert.IsTrue(Unsafe.AreSame(ref array[0], ref span[0]));
819+
}
820+
821+
[TestCategory("Span2DT")]
822+
[TestMethod]
823+
public void Test_Span2DT_TryGetSpan_From2DArray_1()
765824
{
766825
int[,] array =
767826
{
@@ -790,7 +849,7 @@ public void Test_Span2DT_TryGetSpan_1()
790849

791850
[TestCategory("Span2DT")]
792851
[TestMethod]
793-
public void Test_Span2DT_TryGetSpan_2()
852+
public void Test_Span2DT_TryGetSpan_From2DArray_2()
794853
{
795854
int[,] array =
796855
{

0 commit comments

Comments
 (0)