1
1
using System ;
2
- using System . Runtime . CompilerServices ;
3
2
using System . Threading . Tasks ;
4
3
using JetBrains . Annotations ;
5
4
@@ -17,29 +16,27 @@ public static class SpanExtensions
17
16
/// </summary>
18
17
/// <param name="span">The <see cref="Span{T}"/> to fill up</param>
19
18
/// <param name="provider">The values provider to use</param>
20
- public static unsafe void Fill < T > ( this Span < T > span , [ NotNull ] Func < T > provider ) where T : struct
19
+ public static unsafe void Fill < T > ( this Span < T > span , [ NotNull ] Func < T > provider ) where T : unmanaged
21
20
{
22
21
// Fill in parallel
23
22
int
24
23
cores = Environment . ProcessorCount ,
25
24
batch = span . Length / cores ,
26
- mod = span . Length % cores ,
27
- size = Unsafe . SizeOf < T > ( ) ;
28
- ref T r0 = ref span . DangerousGetPinnableReference ( ) ;
29
- fixed ( byte * p0 = & Unsafe . As < T , byte > ( ref r0 ) )
25
+ mod = span . Length % cores ;
26
+ fixed ( T * p0 = span )
30
27
{
31
- byte * pc = p0 ;
28
+ T * pc = p0 ;
32
29
Parallel . For ( 0 , cores , i =>
33
30
{
34
- byte * p = pc + i * batch * size ;
35
- for ( int j = 0 ; j < batch ; j ++ , p += size )
36
- Unsafe . Write ( p , provider ( ) ) ;
31
+ T * p = pc + i * batch ;
32
+ for ( int j = 0 ; j < batch ; j ++ )
33
+ p [ j ] = provider ( ) ;
37
34
} ) . AssertCompleted ( ) ;
38
35
39
36
// Remaining values
40
37
if ( mod < 1 ) return ;
41
38
for ( int i = span . Length - mod ; i < span . Length ; i ++ )
42
- Unsafe . Write ( pc + i * size , provider ( ) ) ;
39
+ pc [ i ] = provider ( ) ;
43
40
}
44
41
}
45
42
@@ -51,11 +48,12 @@ public static unsafe void Fill<T>(this Span<T> span, [NotNull] Func<T> provider)
51
48
/// <param name="w">The number of matrix columns</param>
52
49
[ Pure , NotNull ]
53
50
[ CollectionAccess ( CollectionAccessType . Read ) ]
54
- public static T [ , ] AsMatrix < T > ( this Span < T > span , int h , int w ) where T : struct
51
+ public static unsafe T [ , ] AsMatrix < T > ( this Span < T > span , int h , int w ) where T : unmanaged
55
52
{
56
53
if ( h * w != span . Length ) throw new ArgumentException ( "The input dimensions don't match the source vector size" ) ;
57
54
T [ , ] m = new T [ h , w ] ;
58
- span . CopyTo ( m . AsSpan ( ) ) ;
55
+ fixed ( void * p = m )
56
+ span . CopyTo ( new Span < T > ( p , m . Length ) ) ;
59
57
return m ;
60
58
}
61
59
@@ -65,55 +63,32 @@ public static unsafe void Fill<T>(this Span<T> span, [NotNull] Func<T> provider)
65
63
/// <typeparam name="T">The type of each value in the input <see cref="Span{T}"/></typeparam>
66
64
/// <param name="span">The input <see cref="Span{T}"/> to read</param>
67
65
[ Pure ]
68
- public static unsafe int GetContentHashCode < T > ( this Span < T > span ) where T : struct
66
+ public static unsafe int GetContentHashCode < T > ( this Span < T > span ) where T : unmanaged
69
67
{
70
- fixed ( byte * p0 = & Unsafe . As < T , byte > ( ref span . DangerousGetPinnableReference ( ) ) )
68
+ fixed ( T * p0 = span )
71
69
{
72
- int size = Unsafe . SizeOf < T > ( ) ;
73
70
int hash = 17 ;
74
71
unchecked
75
72
{
76
73
for ( int i = 0 ; i < span . Length ; i ++ )
77
- hash = hash * 23 + Unsafe . Read < T > ( p0 + size * i ) . GetHashCode ( ) ;
74
+ hash = hash * 23 + p0 [ i ] . GetHashCode ( ) ;
78
75
return hash ;
79
76
}
80
77
}
81
78
}
82
79
83
- /// <summary>
84
- /// Returns a deep copy of the input <see cref="Span{T}"/>
85
- /// </summary>
86
- /// <param name="span">The <see cref="Span{T}"/> to clone</param>
87
- /// <remarks>This method avoids the boxing of the <see cref="Array.Clone"/> method, and it is faster thanks to the use of the methods in the <see cref="Buffer"/> class</remarks>
88
- [ Pure ]
89
- [ CollectionAccess ( CollectionAccessType . Read ) ]
90
- public static T [ ] Copy < T > ( this Span < T > span ) where T : struct
91
- {
92
- T [ ] result = new T [ span . Length ] ;
93
- span . CopyTo ( result ) ;
94
- return result ;
95
- }
96
-
97
- /// <summary>
98
- /// Returns a new <see cref="Span{T}"/> instance from the input matrix
99
- /// </summary>
100
- /// <typeparam name="T">The type of the input matrix</typeparam>
101
- /// <param name="m">The input matrix</param>
102
- [ Pure ]
103
- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
104
- public static Span < T > AsSpan < T > ( [ NotNull ] this T [ , ] m ) where T : struct => Span < T > . DangerousCreate ( m , ref m [ 0 , 0 ] , m . Length ) ;
105
-
106
80
/// <summary>
107
81
/// Extracts a single row from a given matrix
108
82
/// </summary>
109
83
/// <param name="m">The source matrix</param>
110
84
/// <param name="row">The target row to return</param>
111
- [ Pure ]
85
+ [ Pure , NotNull ]
112
86
[ CollectionAccess ( CollectionAccessType . Read ) ]
113
- public static Span < T > Slice < T > ( [ NotNull ] this T [ , ] m , int row ) where T : struct
87
+ public static unsafe T [ ] Slice < T > ( [ NotNull ] this T [ , ] m , int row ) where T : unmanaged
114
88
{
115
89
if ( row < 0 || row > m . GetLength ( 0 ) - 1 ) throw new ArgumentOutOfRangeException ( nameof ( row ) , "The row index isn't valid" ) ;
116
- return Span < T > . DangerousCreate ( m , ref m [ row , 0 ] , m . GetLength ( 1 ) ) ;
90
+ int wm = m . GetLength ( 1 ) ;
91
+ fixed ( T * p = m ) return new Span < T > ( p + row * wm , wm ) . ToArray ( ) ;
117
92
}
118
93
119
94
#endregion
@@ -131,7 +106,7 @@ public static unsafe int Argmax(this Span<float> span)
131
106
if ( span . Length < 2 ) return default ;
132
107
int index = 0 ;
133
108
float max = float . MinValue ;
134
- fixed ( float * p = & span . DangerousGetPinnableReference ( ) )
109
+ fixed ( float * p = span )
135
110
{
136
111
for ( int j = 0 ; j < span . Length ; j ++ )
137
112
{
@@ -158,7 +133,7 @@ public static unsafe int Argmax(this Span<float> span)
158
133
internal static unsafe bool MatchElementwiseThreshold ( this Span < float > x1 , Span < float > x2 , float threshold )
159
134
{
160
135
if ( x1 . Length != x2 . Length ) throw new ArgumentException ( "The two input spans must have the same length" ) ;
161
- fixed ( float * px1 = & x1 . DangerousGetPinnableReference ( ) , px2 = & x2 . DangerousGetPinnableReference ( ) )
136
+ fixed ( float * px1 = x1 , px2 = x2 )
162
137
for ( int i = 0 ; i < x1 . Length ; i ++ )
163
138
if ( px1 [ i ] > threshold != px2 [ i ] > threshold )
164
139
return false ;
@@ -177,7 +152,7 @@ internal static unsafe bool MatchElementwiseThreshold(this Span<float> x1, Span<
177
152
internal static unsafe bool IsCloseTo ( this Span < float > x1 , Span < float > x2 , float threshold )
178
153
{
179
154
if ( x1 . Length != x2 . Length ) throw new ArgumentException ( "The two input spans must have the same length" ) ;
180
- fixed ( float * px1 = & x1 . DangerousGetPinnableReference ( ) , px2 = & x2 . DangerousGetPinnableReference ( ) )
155
+ fixed ( float * px1 = x1 , px2 = x2 )
181
156
for ( int i = 0 ; i < x1 . Length ; i ++ )
182
157
if ( ( px1 [ i ] - px2 [ i ] ) . Abs ( ) > threshold )
183
158
return false ;
0 commit comments