From 6a0d611020be82179838c14e7dce5480e2a5f1f8 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 15 May 2023 16:25:21 +0200 Subject: [PATCH] Improve XML docs for Span2D.Slice(int, int, int, int) --- .../Memory/Memory2D{T}.cs | 3 ++- .../Memory/ReadOnlyMemory2D{T}.cs | 3 ++- .../Memory/ReadOnlySpan2D{T}.cs | 3 ++- .../Memory/Span2D{T}.cs | 25 ++++++++++++++++++- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/CommunityToolkit.HighPerformance/Memory/Memory2D{T}.cs b/src/CommunityToolkit.HighPerformance/Memory/Memory2D{T}.cs index 462998d09..2b7b09b40 100644 --- a/src/CommunityToolkit.HighPerformance/Memory/Memory2D{T}.cs +++ b/src/CommunityToolkit.HighPerformance/Memory/Memory2D{T}.cs @@ -652,11 +652,12 @@ public Span2D Span /// The target column to map within the current instance. /// The height to map within the current instance. /// The width to map within the current instance. - /// + /// /// Thrown when either , or /// are negative or not within the bounds that are valid for the current instance. /// /// A new instance representing a slice of the current one. + /// See additional remarks in the docs. public unsafe Memory2D Slice(int row, int column, int height, int width) { if ((uint)row >= Height) diff --git a/src/CommunityToolkit.HighPerformance/Memory/ReadOnlyMemory2D{T}.cs b/src/CommunityToolkit.HighPerformance/Memory/ReadOnlyMemory2D{T}.cs index 5bc054092..7c57e620c 100644 --- a/src/CommunityToolkit.HighPerformance/Memory/ReadOnlyMemory2D{T}.cs +++ b/src/CommunityToolkit.HighPerformance/Memory/ReadOnlyMemory2D{T}.cs @@ -665,11 +665,12 @@ public ReadOnlySpan2D Span /// The target column to map within the current instance. /// The height to map within the current instance. /// The width to map within the current instance. - /// + /// /// Thrown when either , or /// are negative or not within the bounds that are valid for the current instance. /// /// A new instance representing a slice of the current one. + /// See additional remarks in the docs. public unsafe ReadOnlyMemory2D Slice(int row, int column, int height, int width) { if ((uint)row >= Height) diff --git a/src/CommunityToolkit.HighPerformance/Memory/ReadOnlySpan2D{T}.cs b/src/CommunityToolkit.HighPerformance/Memory/ReadOnlySpan2D{T}.cs index 27110c3a2..bbdbe6a1c 100644 --- a/src/CommunityToolkit.HighPerformance/Memory/ReadOnlySpan2D{T}.cs +++ b/src/CommunityToolkit.HighPerformance/Memory/ReadOnlySpan2D{T}.cs @@ -842,11 +842,12 @@ public ref T DangerousGetReferenceAt(int i, int j) /// The target column to map within the current instance. /// The height to map within the current instance. /// The width to map within the current instance. - /// + /// /// Thrown when either , or /// are negative or not within the bounds that are valid for the current instance. /// /// A new instance representing a slice of the current one. + /// See additional remarks in the docs. public unsafe ReadOnlySpan2D Slice(int row, int column, int height, int width) { if ((uint)row >= Height) diff --git a/src/CommunityToolkit.HighPerformance/Memory/Span2D{T}.cs b/src/CommunityToolkit.HighPerformance/Memory/Span2D{T}.cs index 11e4ab162..992269292 100644 --- a/src/CommunityToolkit.HighPerformance/Memory/Span2D{T}.cs +++ b/src/CommunityToolkit.HighPerformance/Memory/Span2D{T}.cs @@ -999,11 +999,34 @@ public ref T DangerousGetReferenceAt(int i, int j) /// The target column to map within the current instance. /// The height to map within the current instance. /// The width to map within the current instance. - /// + /// /// Thrown when either , or /// are negative or not within the bounds that are valid for the current instance. /// /// A new instance representing a slice of the current one. + /// + /// + /// Contrary to , this method will throw an + /// if attempting to perform a slice operation that would result in either axes being 0. That is, trying to call + /// as eg. Slice(row: 1, column: 0, height: 0, width: 2) on an instance + /// that has 1 row and 2 columns will throw, rather than returning a new instance with 0 rows and + /// 2 columns. For contrast, trying to eg. call Slice(start: 1, length: 0) on a instance of + /// length 1 would return a span of length 0, with the internal reference being set to right past the end of the memory. + /// + /// + /// This is by design, and it is due to the internal memory layout that has. That is, in the case + /// of , the only edge case scenario would be to obtain a new span of size 0, referencing the very end + /// of the backing object (eg. an array or a instance). In that case, the GC can correctly track things. + /// With , on the other hand, it would be possible to slice an instance with a sizeof 0 in either axis, + /// but with the computed starting reference pointing well past the end of the internal memory area. Such a behavior would not + /// be valid if the reference was pointing to a managed object, and it would cause memory corruptions (ie. "GC holes"). + /// + /// + /// If you specifically need to be able to obtain empty values from slicing past the valid range, consider performing the range + /// validation yourself (ie. through some helper method), and then only invoking once the + /// parameters are in the accepted range. Otherwise, consider returning another return explicitly, such as . + /// + /// public unsafe Span2D Slice(int row, int column, int height, int width) { if ((uint)row >= Height)