33// See the LICENSE file in the project root for more information.
44
55using System ;
6+ using System . Buffers ;
67using System . IO ;
78using System . Runtime . CompilerServices ;
89using System . Runtime . InteropServices ;
@@ -142,6 +143,260 @@ public void Test_MemoryExtensions_FromArray_CastFromByteAndBack()
142143 Assert . IsTrue ( span1 == span2 ) ;
143144 }
144145
146+ [ TestCategory ( "MemoryExtensions" ) ]
147+ [ TestMethod ]
148+ public void Test_MemoryExtensions_Cast_TooShort_WithSlice ( )
149+ {
150+ Memory < byte > m1 = new byte [ 8 ] . AsMemory ( ) . Slice ( 4 , 3 ) ;
151+ Memory < int > mc1 = m1 . Cast < byte , int > ( ) ;
152+
153+ Assert . IsTrue ( mc1 . IsEmpty ) ;
154+
155+ Memory < byte > m2 = new byte [ 20 ] . AsMemory ( ) . Slice ( 4 , 13 ) ;
156+ Memory < float > mc2 = m2 . Cast < byte , float > ( ) ;
157+
158+ Assert . AreEqual ( mc2 . Length , 3 ) ;
159+
160+ Memory < byte > m3 = new byte [ 16 ] . AsMemory ( ) . Slice ( 5 ) ;
161+ Memory < float > mc3 = m3 . Cast < byte , float > ( ) ;
162+
163+ Assert . AreEqual ( mc3 . Length , 2 ) ;
164+ }
165+
166+ [ TestCategory ( "MemoryExtensions" ) ]
167+ [ TestMethod ]
168+ public void Test_MemoryExtensions_FromArray_CastFromByte_WithSlice ( )
169+ {
170+ Memory < byte > memoryOfBytes = new byte [ 512 ] . AsMemory ( ) . Slice ( 128 , 128 ) ;
171+ Memory < float > memoryOfFloats = memoryOfBytes . Cast < byte , float > ( ) ;
172+
173+ Assert . AreEqual ( memoryOfFloats . Length , 128 / sizeof ( float ) ) ;
174+
175+ Span < byte > spanOfBytes = memoryOfBytes . Span ;
176+ Span < float > spanOfFloats = memoryOfFloats . Span ;
177+
178+ Assert . AreEqual ( memoryOfFloats . Length , spanOfFloats . Length ) ;
179+ Assert . IsTrue ( Unsafe . AreSame (
180+ ref spanOfBytes [ 0 ] ,
181+ ref Unsafe . As < float , byte > ( ref spanOfFloats [ 0 ] ) ) ) ;
182+ }
183+
184+ [ TestCategory ( "MemoryExtensions" ) ]
185+ [ TestMethod ]
186+ public void Test_MemoryExtensions_FromArray_CastToByte_WithSlice ( )
187+ {
188+ Memory < float > memoryOfFloats = new float [ 512 ] . AsMemory ( ) . Slice ( 128 , 128 ) ;
189+ Memory < byte > memoryOfBytes = memoryOfFloats . Cast < float , byte > ( ) ;
190+
191+ Assert . AreEqual ( memoryOfBytes . Length , 128 * sizeof ( float ) ) ;
192+
193+ Span < float > spanOfFloats = memoryOfFloats . Span ;
194+ Span < byte > spanOfBytes = memoryOfBytes . Span ;
195+
196+ Assert . AreEqual ( memoryOfBytes . Length , spanOfBytes . Length ) ;
197+ Assert . IsTrue ( Unsafe . AreSame (
198+ ref spanOfFloats [ 0 ] ,
199+ ref Unsafe . As < byte , float > ( ref spanOfBytes [ 0 ] ) ) ) ;
200+ }
201+
202+ [ TestCategory ( "MemoryExtensions" ) ]
203+ [ TestMethod ]
204+ public void Test_MemoryExtensions_FromArray_CastToShort_WithSlice ( )
205+ {
206+ Memory < float > memoryOfFloats = new float [ 512 ] . AsMemory ( ) . Slice ( 128 , 128 ) ;
207+ Memory < short > memoryOfShorts = memoryOfFloats . Cast < float , short > ( ) ;
208+
209+ Assert . AreEqual ( memoryOfShorts . Length , 128 * sizeof ( float ) / sizeof ( short ) ) ;
210+
211+ Span < float > spanOfFloats = memoryOfFloats . Span ;
212+ Span < short > spanOfShorts = memoryOfShorts . Span ;
213+
214+ Assert . AreEqual ( memoryOfShorts . Length , spanOfShorts . Length ) ;
215+ Assert . IsTrue ( Unsafe . AreSame (
216+ ref spanOfFloats [ 0 ] ,
217+ ref Unsafe . As < short , float > ( ref spanOfShorts [ 0 ] ) ) ) ;
218+ }
219+
220+ [ TestCategory ( "MemoryExtensions" ) ]
221+ [ TestMethod ]
222+ public void Test_MemoryExtensions_FromArray_CastFromByteAndBack_WithSlice ( )
223+ {
224+ var data = new byte [ 512 ] ;
225+ Memory < byte > memoryOfBytes = data . AsMemory ( ) . Slice ( 128 , 128 ) ;
226+ Memory < float > memoryOfFloats = memoryOfBytes . Cast < byte , float > ( ) ;
227+ Memory < byte > memoryBack = memoryOfFloats . Cast < float , byte > ( ) ;
228+
229+ Assert . AreEqual ( memoryOfBytes . Length , memoryBack . Length ) ;
230+
231+ Assert . IsTrue ( MemoryMarshal . TryGetArray < byte > ( memoryBack , out var segment ) ) ;
232+ Assert . AreSame ( segment . Array ! , data ) ;
233+ Assert . AreEqual ( segment . Offset , 128 ) ;
234+ Assert . AreEqual ( segment . Count , 128 ) ;
235+
236+ Assert . IsTrue ( memoryOfBytes . Equals ( memoryBack ) ) ;
237+
238+ Span < byte > span1 = memoryOfBytes . Span ;
239+ Span < byte > span2 = memoryBack . Span ;
240+
241+ Assert . IsTrue ( span1 == span2 ) ;
242+ }
243+
244+ [ TestCategory ( "MemoryExtensions" ) ]
245+ [ TestMethod ]
246+ public void Test_MemoryExtensions_FromMemoryManager_CastFromByte ( )
247+ {
248+ Memory < byte > memoryOfBytes = new ArrayMemoryManager < byte > ( 128 ) ;
249+ Memory < float > memoryOfFloats = memoryOfBytes . Cast < byte , float > ( ) ;
250+
251+ Assert . AreEqual ( memoryOfFloats . Length , 128 / sizeof ( float ) ) ;
252+
253+ Span < byte > spanOfBytes = memoryOfBytes . Span ;
254+ Span < float > spanOfFloats = memoryOfFloats . Span ;
255+
256+ Assert . AreEqual ( memoryOfFloats . Length , spanOfFloats . Length ) ;
257+ Assert . IsTrue ( Unsafe . AreSame (
258+ ref spanOfBytes [ 0 ] ,
259+ ref Unsafe . As < float , byte > ( ref spanOfFloats [ 0 ] ) ) ) ;
260+ }
261+
262+ [ TestCategory ( "MemoryExtensions" ) ]
263+ [ TestMethod ]
264+ public void Test_MemoryExtensions_FromMemoryManager_CastToByte ( )
265+ {
266+ Memory < float > memoryOfFloats = new ArrayMemoryManager < float > ( 128 ) ;
267+ Memory < byte > memoryOfBytes = memoryOfFloats . Cast < float , byte > ( ) ;
268+
269+ Assert . AreEqual ( memoryOfBytes . Length , 128 * sizeof ( float ) ) ;
270+
271+ Span < float > spanOfFloats = memoryOfFloats . Span ;
272+ Span < byte > spanOfBytes = memoryOfBytes . Span ;
273+
274+ Assert . AreEqual ( memoryOfBytes . Length , spanOfBytes . Length ) ;
275+ Assert . IsTrue ( Unsafe . AreSame (
276+ ref spanOfFloats [ 0 ] ,
277+ ref Unsafe . As < byte , float > ( ref spanOfBytes [ 0 ] ) ) ) ;
278+ }
279+
280+ [ TestCategory ( "MemoryExtensions" ) ]
281+ [ TestMethod ]
282+ public void Test_MemoryExtensions_FromMemoryManager_CastToShort ( )
283+ {
284+ Memory < float > memoryOfFloats = new ArrayMemoryManager < float > ( 128 ) ;
285+ Memory < short > memoryOfShorts = memoryOfFloats . Cast < float , short > ( ) ;
286+
287+ Assert . AreEqual ( memoryOfShorts . Length , 128 * sizeof ( float ) / sizeof ( short ) ) ;
288+
289+ Span < float > spanOfFloats = memoryOfFloats . Span ;
290+ Span < short > spanOfShorts = memoryOfShorts . Span ;
291+
292+ Assert . AreEqual ( memoryOfShorts . Length , spanOfShorts . Length ) ;
293+ Assert . IsTrue ( Unsafe . AreSame (
294+ ref spanOfFloats [ 0 ] ,
295+ ref Unsafe . As < short , float > ( ref spanOfShorts [ 0 ] ) ) ) ;
296+ }
297+
298+ [ TestCategory ( "MemoryExtensions" ) ]
299+ [ TestMethod ]
300+ public void Test_MemoryExtensions_FromMemoryManager_CastFromByteAndBack ( )
301+ {
302+ var data = new ArrayMemoryManager < byte > ( 128 ) ;
303+ Memory < byte > memoryOfBytes = data ;
304+ Memory < float > memoryOfFloats = memoryOfBytes . Cast < byte , float > ( ) ;
305+ Memory < byte > memoryBack = memoryOfFloats . Cast < float , byte > ( ) ;
306+
307+ Assert . AreEqual ( memoryOfBytes . Length , memoryBack . Length ) ;
308+
309+ Assert . IsTrue ( MemoryMarshal . TryGetMemoryManager < byte , ArrayMemoryManager < byte > > ( memoryBack , out var manager , out var start , out var length ) ) ;
310+ Assert . AreSame ( manager ! , data ) ;
311+ Assert . AreEqual ( start , 0 ) ;
312+ Assert . AreEqual ( length , 128 ) ;
313+
314+ Assert . IsTrue ( memoryOfBytes . Equals ( memoryBack ) ) ;
315+
316+ Span < byte > span1 = memoryOfBytes . Span ;
317+ Span < byte > span2 = memoryBack . Span ;
318+
319+ Assert . IsTrue ( span1 == span2 ) ;
320+ }
321+
322+ [ TestCategory ( "MemoryExtensions" ) ]
323+ [ TestMethod ]
324+ public void Test_MemoryExtensions_FromMemoryManager_CastFromByte_WithSlice ( )
325+ {
326+ Memory < byte > memoryOfBytes = new ArrayMemoryManager < byte > ( 512 ) . Memory . Slice ( 128 , 128 ) ;
327+ Memory < float > memoryOfFloats = memoryOfBytes . Cast < byte , float > ( ) ;
328+
329+ Assert . AreEqual ( memoryOfFloats . Length , 128 / sizeof ( float ) ) ;
330+
331+ Span < byte > spanOfBytes = memoryOfBytes . Span ;
332+ Span < float > spanOfFloats = memoryOfFloats . Span ;
333+
334+ Assert . AreEqual ( memoryOfFloats . Length , spanOfFloats . Length ) ;
335+ Assert . IsTrue ( Unsafe . AreSame (
336+ ref spanOfBytes [ 0 ] ,
337+ ref Unsafe . As < float , byte > ( ref spanOfFloats [ 0 ] ) ) ) ;
338+ }
339+
340+ [ TestCategory ( "MemoryExtensions" ) ]
341+ [ TestMethod ]
342+ public void Test_MemoryExtensions_FromMemoryManager_CastToByte_WithSlice ( )
343+ {
344+ Memory < float > memoryOfFloats = new ArrayMemoryManager < float > ( 512 ) . Memory . Slice ( 128 , 128 ) ;
345+ Memory < byte > memoryOfBytes = memoryOfFloats . Cast < float , byte > ( ) ;
346+
347+ Assert . AreEqual ( memoryOfBytes . Length , 128 * sizeof ( float ) ) ;
348+
349+ Span < float > spanOfFloats = memoryOfFloats . Span ;
350+ Span < byte > spanOfBytes = memoryOfBytes . Span ;
351+
352+ Assert . AreEqual ( memoryOfBytes . Length , spanOfBytes . Length ) ;
353+ Assert . IsTrue ( Unsafe . AreSame (
354+ ref spanOfFloats [ 0 ] ,
355+ ref Unsafe . As < byte , float > ( ref spanOfBytes [ 0 ] ) ) ) ;
356+ }
357+
358+ [ TestCategory ( "MemoryExtensions" ) ]
359+ [ TestMethod ]
360+ public void Test_MemoryExtensions_FromMemoryManager_CastToShort_WithSlice ( )
361+ {
362+ Memory < float > memoryOfFloats = new ArrayMemoryManager < float > ( 512 ) . Memory . Slice ( 128 , 128 ) ;
363+ Memory < short > memoryOfShorts = memoryOfFloats . Cast < float , short > ( ) ;
364+
365+ Assert . AreEqual ( memoryOfShorts . Length , 128 * sizeof ( float ) / sizeof ( short ) ) ;
366+
367+ Span < float > spanOfFloats = memoryOfFloats . Span ;
368+ Span < short > spanOfShorts = memoryOfShorts . Span ;
369+
370+ Assert . AreEqual ( memoryOfShorts . Length , spanOfShorts . Length ) ;
371+ Assert . IsTrue ( Unsafe . AreSame (
372+ ref spanOfFloats [ 0 ] ,
373+ ref Unsafe . As < short , float > ( ref spanOfShorts [ 0 ] ) ) ) ;
374+ }
375+
376+ [ TestCategory ( "MemoryExtensions" ) ]
377+ [ TestMethod ]
378+ public void Test_MemoryExtensions_FromMemoryManager_CastFromByteAndBack_WithSlice ( )
379+ {
380+ var data = new ArrayMemoryManager < byte > ( 512 ) ;
381+ Memory < byte > memoryOfBytes = data . Memory . Slice ( 128 , 128 ) ;
382+ Memory < float > memoryOfFloats = memoryOfBytes . Cast < byte , float > ( ) ;
383+ Memory < byte > memoryBack = memoryOfFloats . Cast < float , byte > ( ) ;
384+
385+ Assert . AreEqual ( memoryOfBytes . Length , memoryBack . Length ) ;
386+
387+ Assert . IsTrue ( MemoryMarshal . TryGetMemoryManager < byte , ArrayMemoryManager < byte > > ( memoryBack , out var manager , out var start , out var length ) ) ;
388+ Assert . AreSame ( manager ! , data ) ;
389+ Assert . AreEqual ( start , 128 ) ;
390+ Assert . AreEqual ( length , 128 ) ;
391+
392+ Assert . IsTrue ( memoryOfBytes . Equals ( memoryBack ) ) ;
393+
394+ Span < byte > span1 = memoryOfBytes . Span ;
395+ Span < byte > span2 = memoryBack . Span ;
396+
397+ Assert . IsTrue ( span1 == span2 ) ;
398+ }
399+
145400 [ TestCategory ( "MemoryExtensions" ) ]
146401 [ TestMethod ]
147402 public void Test_MemoryExtensions_EmptyMemoryStream ( )
@@ -167,5 +422,43 @@ public void Test_MemoryExtensions_MemoryStream()
167422 Assert . AreEqual ( stream . Length , memory . Length ) ;
168423 Assert . IsTrue ( stream . CanWrite ) ;
169424 }
425+
426+ private sealed class ArrayMemoryManager < T > : MemoryManager < T >
427+ where T : unmanaged
428+ {
429+ private readonly T [ ] array ;
430+
431+ public ArrayMemoryManager ( int size )
432+ {
433+ this . array = new T [ size ] ;
434+ }
435+
436+ public override Span < T > GetSpan ( )
437+ {
438+ return this . array ;
439+ }
440+
441+ public override unsafe MemoryHandle Pin ( int elementIndex = 0 )
442+ {
443+ GCHandle handle = GCHandle . Alloc ( this . array , GCHandleType . Pinned ) ;
444+ ref T r0 = ref this . array [ elementIndex ] ;
445+ void * p = Unsafe . AsPointer ( ref r0 ) ;
446+
447+ return new MemoryHandle ( p , handle ) ;
448+ }
449+
450+ public override void Unpin ( )
451+ {
452+ }
453+
454+ protected override void Dispose ( bool disposing )
455+ {
456+ }
457+
458+ public static implicit operator Memory < T > ( ArrayMemoryManager < T > memoryManager )
459+ {
460+ return memoryManager . Memory ;
461+ }
462+ }
170463 }
171464}
0 commit comments