@@ -999,11 +999,34 @@ public ref T DangerousGetReferenceAt(int i, int j)
999
999
/// <param name="column">The target column to map within the current instance.</param>
1000
1000
/// <param name="height">The height to map within the current instance.</param>
1001
1001
/// <param name="width">The width to map within the current instance.</param>
1002
- /// <exception cref="ArgumentException ">
1002
+ /// <exception cref="ArgumentOutOfRangeException ">
1003
1003
/// Thrown when either <paramref name="height"/>, <paramref name="width"/> or <paramref name="height"/>
1004
1004
/// are negative or not within the bounds that are valid for the current instance.
1005
1005
/// </exception>
1006
1006
/// <returns>A new <see cref="Span2D{T}"/> instance representing a slice of the current one.</returns>
1007
+ /// <remarks>
1008
+ /// <para>
1009
+ /// Contrary to <see cref="Span{T}.Slice(int, int)"/>, this method will throw an <see cref="ArgumentOutOfRangeException"/>
1010
+ /// if attempting to perform a slice operation that would result in either axes being 0. That is, trying to call
1011
+ /// <see cref="Slice(int, int, int, int)"/> as eg. <c>Slice(row: 1, column: 0, height: 0, width: 2)</c> on an instance
1012
+ /// that has 1 row and 2 columns will throw, rather than returning a new <see cref="Span2D{T}"/> instance with 0 rows and
1013
+ /// 2 columns. For contrast, trying to eg. call <c>Slice(start: 1, length: 0)</c> on a <see cref="Span{T}"/> instance of
1014
+ /// length 1 would return a span of length 0, with the internal reference being set to right past the end of the memory.
1015
+ /// </para>
1016
+ /// <para>
1017
+ /// This is by design, and it is due to the internal memory layout that <see cref="Span2D{T}"/> has. That is, in the case
1018
+ /// of <see cref="Span{T}"/>, the only edge case scenario would be to obtain a new span of size 0, referencing the very end
1019
+ /// of the backing object (eg. an array or a <see cref="string"/> instance). In that case, the GC can correctly track things.
1020
+ /// With <see cref="Span2D{T}"/>, on the other hand, it would be possible to slice an instance with a sizeof 0 in either axis,
1021
+ /// but with the computed starting reference pointing well past the end of the internal memory area. Such a behavior would not
1022
+ /// be valid if the reference was pointing to a managed object, and it would cause memory corruptions (ie. "GC holes").
1023
+ /// </para>
1024
+ /// <para>
1025
+ /// If you specifically need to be able to obtain empty values from slicing past the valid range, consider performing the range
1026
+ /// validation yourself (ie. through some helper method), and then only invoking <see cref="Slice(int, int, int, int)"/> once the
1027
+ /// parameters are in the accepted range. Otherwise, consider returning another return explicitly, such as <see cref="Empty"/>.
1028
+ /// </para>
1029
+ /// </remarks>
1007
1030
public unsafe Span2D < T > Slice ( int row , int column , int height , int width )
1008
1031
{
1009
1032
if ( ( uint ) row >= Height )
0 commit comments