11// Licensed to the .NET Foundation under one or more agreements.
22// The .NET Foundation licenses this file to you under the MIT license.
3+ // Simplified for NumSharp - only supports unmanaged types (no reference type handling)
34
4- using System . Diagnostics ;
5- using System . Diagnostics . CodeAnalysis ;
5+ using System ;
66using System . Runtime . CompilerServices ;
77using System . Runtime . InteropServices ;
8- using System . Threading ;
98
10- namespace System
9+ namespace NumSharp . Utilities
1110{
11+ /// <summary>
12+ /// Provides low-level memory copy operations for unmanaged types.
13+ /// </summary>
1214 public static partial class UnmanagedBuffer
1315 {
14- // Copies from one primitive array to another primitive array without
15- // respecting types. This calls memmove internally. The count and
16- // offset parameters here are in bytes. If you want to use traditional
17- // array element indices and counts, use Array.Copy.
18- public static void BlockCopy ( Array src , int srcOffset , Array dst , int dstOffset , int count )
19- {
20- ArgumentNullException . ThrowIfNull ( src ) ;
21- ArgumentNullException . ThrowIfNull ( dst ) ;
22-
23- nuint uSrcLen = src . NativeLength ;
24- if ( src . GetType ( ) != typeof ( byte [ ] ) )
25- {
26- if ( ! src . GetCorElementTypeOfElementType ( ) . IsPrimitiveType ( ) )
27- throw new ArgumentException ( SR . Arg_MustBePrimArray , nameof ( src ) ) ;
28- uSrcLen *= ( nuint ) src . GetElementSize ( ) ;
29- }
30-
31- nuint uDstLen = uSrcLen ;
32- if ( src != dst )
33- {
34- uDstLen = dst . NativeLength ;
35- if ( dst . GetType ( ) != typeof ( byte [ ] ) )
36- {
37- if ( ! dst . GetCorElementTypeOfElementType ( ) . IsPrimitiveType ( ) )
38- throw new ArgumentException ( SR . Arg_MustBePrimArray , nameof ( dst ) ) ;
39- uDstLen *= ( nuint ) dst . GetElementSize ( ) ;
40- }
41- }
42-
43- ArgumentOutOfRangeException . ThrowIfNegative ( srcOffset ) ;
44- ArgumentOutOfRangeException . ThrowIfNegative ( dstOffset ) ;
45- ArgumentOutOfRangeException . ThrowIfNegative ( count ) ;
46-
47- nuint uCount = ( nuint ) count ;
48- nuint uSrcOffset = ( nuint ) srcOffset ;
49- nuint uDstOffset = ( nuint ) dstOffset ;
50-
51- if ( ( uSrcLen < uSrcOffset + uCount ) || ( uDstLen < uDstOffset + uCount ) )
52- throw new ArgumentException ( SR . Argument_InvalidOffLen ) ;
53-
54- Memmove ( ref Unsafe . AddByteOffset ( ref MemoryMarshal . GetArrayDataReference ( dst ) , uDstOffset ) , ref Unsafe . AddByteOffset ( ref MemoryMarshal . GetArrayDataReference ( src ) , uSrcOffset ) , uCount ) ;
55- }
56-
57- public static int ByteLength ( Array array )
58- {
59- ArgumentNullException . ThrowIfNull ( array ) ;
60-
61- // Is it of primitive types?
62- if ( ! array . GetCorElementTypeOfElementType ( ) . IsPrimitiveType ( ) )
63- throw new ArgumentException ( SR . Arg_MustBePrimArray , nameof ( array ) ) ;
64-
65- nuint byteLength = array . NativeLength * ( nuint ) array . GetElementSize ( ) ;
66-
67- // This API is exposed both as UnmanagedBuffer.ByteLength and also used indirectly in argument
68- // checks for UnmanagedBuffer.GetByte/SetByte.
69- //
70- // If somebody called Get/SetByte on 2GB+ arrays, there is a decent chance that
71- // the computation of the index has overflowed. Thus we intentionally always
72- // throw on 2GB+ arrays in Get/SetByte argument checks (even for indices <2GB)
73- // to prevent people from running into a trap silently.
74-
75- return checked ( ( int ) byteLength ) ;
76- }
77-
78- public static byte GetByte ( Array array , int index )
79- {
80- // array argument validation done via ByteLength
81- if ( ( uint ) index >= ( uint ) ByteLength ( array ) )
82- {
83- ThrowHelper . ThrowArgumentOutOfRangeException ( ExceptionArgument . index ) ;
84- }
85-
86- return Unsafe . Add ( ref MemoryMarshal . GetArrayDataReference ( array ) , index ) ;
87- }
88-
89- public static void SetByte ( Array array , int index , byte value )
90- {
91- // array argument validation done via ByteLength
92- if ( ( uint ) index >= ( uint ) ByteLength ( array ) )
93- {
94- ThrowHelper . ThrowArgumentOutOfRangeException ( ExceptionArgument . index ) ;
95- }
96-
97- Unsafe . Add ( ref MemoryMarshal . GetArrayDataReference ( array ) , index ) = value;
98- }
99-
100- // The attributes on this method are chosen for best JIT performance.
101- // Please do not edit unless intentional.
16+ /// <summary>
17+ /// Copies bytes from source to destination using unmanaged memory copy.
18+ /// </summary>
10219 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
10320 [ CLSCompliant ( false ) ]
104- [ RequiresUnsafe ]
10521 public static unsafe void MemoryCopy ( void * source , void * destination , long destinationSizeInBytes , long sourceBytesToCopy )
10622 {
10723 if ( sourceBytesToCopy > destinationSizeInBytes )
@@ -112,11 +28,11 @@ public static unsafe void MemoryCopy(void* source, void* destination, long desti
11228 Memmove ( ref * ( byte * ) destination , ref * ( byte * ) source , checked ( ( nuint ) sourceBytesToCopy ) ) ;
11329 }
11430
115- // The attributes on this method are chosen for best JIT performance.
116- // Please do not edit unless intentional.
31+ /// <summary>
32+ /// Copies bytes from source to destination using unmanaged memory copy.
33+ /// </summary>
11734 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
11835 [ CLSCompliant ( false ) ]
119- [ RequiresUnsafe ]
12036 public static unsafe void MemoryCopy ( void * source , void * destination , ulong destinationSizeInBytes , ulong sourceBytesToCopy )
12137 {
12238 if ( sourceBytesToCopy > destinationSizeInBytes )
@@ -127,88 +43,30 @@ public static unsafe void MemoryCopy(void* source, void* destination, ulong dest
12743 Memmove ( ref * ( byte * ) destination , ref * ( byte * ) source , checked ( ( nuint ) sourceBytesToCopy ) ) ;
12844 }
12945
130- #if ! MONO // Mono BulkMoveWithWriteBarrier is in terms of elements (not bytes) and takes a type handle.
131-
132- [ Intrinsic ]
46+ /// <summary>
47+ /// Copies elements from source to destination.
48+ /// For unmanaged types only - does not handle reference types.
49+ /// </summary>
13350 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
134- internal static unsafe void Memmove < T > ( ref T destination , ref T source , nuint elementCount )
135- {
136- if ( ! RuntimeHelpers . IsReferenceOrContainsReferences < T > ( ) )
137- {
138- // Blittable memmove
139- UnmanagedSpanHelpers . Memmove (
140- ref Unsafe . As < T , byte > ( ref destination ) ,
141- ref Unsafe . As < T , byte > ( ref source ) ,
142- elementCount * ( nuint ) sizeof ( T ) ) ;
143- }
144- else
145- {
146- // Non-blittable memmove
147- BulkMoveWithWriteBarrier (
148- ref Unsafe . As < T , byte > ( ref destination ) ,
149- ref Unsafe . As < T , byte > ( ref source ) ,
150- elementCount * ( nuint ) sizeof ( T ) ) ;
151- }
152- }
153-
154- // The maximum block size to for BulkMoveWithWriteBarrierInternal FCall. This is required to avoid GC starvation.
155- #if DEBUG // Stress the mechanism in debug builds
156- private const uint BulkMoveWithWriteBarrierChunk = 0x400 ;
157- #else
158- private const uint BulkMoveWithWriteBarrierChunk = 0x4000 ;
159- #endif
160-
161- internal static void BulkMoveWithWriteBarrier ( ref byte destination , ref byte source , nuint byteCount )
51+ internal static unsafe void Memmove < T > ( ref T destination , ref T source , nuint elementCount ) where T : unmanaged
16252 {
163- if ( byteCount <= BulkMoveWithWriteBarrierChunk )
164- {
165- BulkMoveWithWriteBarrierInternal ( ref destination , ref source , byteCount ) ;
166- Thread . FastPollGC ( ) ;
167- }
168- else
169- {
170- BulkMoveWithWriteBarrierBatch ( ref destination , ref source , byteCount ) ;
171- }
53+ UnmanagedSpanHelpers . Memmove (
54+ ref Unsafe . As < T , byte > ( ref destination ) ,
55+ ref Unsafe . As < T , byte > ( ref source ) ,
56+ elementCount * ( nuint ) sizeof ( T ) ) ;
17257 }
17358
174- // Non-inlinable wrapper around the loop for copying large blocks in chunks
175- [ MethodImpl ( MethodImplOptions . NoInlining ) ]
176- private static void BulkMoveWithWriteBarrierBatch ( ref byte destination , ref byte source , nuint byteCount )
59+ /// <summary>
60+ /// Copies elements from source to destination with ulong element count.
61+ /// For unmanaged types only - does not handle reference types.
62+ /// </summary>
63+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
64+ internal static unsafe void Memmove < T > ( ref T destination , ref T source , ulong elementCount ) where T : unmanaged
17765 {
178- Debug . Assert ( byteCount > BulkMoveWithWriteBarrierChunk ) ;
179-
180- if ( Unsafe . AreSame ( ref source , ref destination ) )
181- return ;
182-
183- // This is equivalent to: (destination - source) >= byteCount || (destination - source) < 0
184- if ( ( nuint ) ( nint ) Unsafe . ByteOffset ( ref source , ref destination ) >= byteCount )
185- {
186- // Copy forwards
187- do
188- {
189- byteCount -= BulkMoveWithWriteBarrierChunk ;
190- BulkMoveWithWriteBarrierInternal ( ref destination , ref source , BulkMoveWithWriteBarrierChunk ) ;
191- Thread . FastPollGC ( ) ;
192- destination = ref Unsafe . AddByteOffset ( ref destination , BulkMoveWithWriteBarrierChunk ) ;
193- source = ref Unsafe . AddByteOffset ( ref source , BulkMoveWithWriteBarrierChunk ) ;
194- }
195- while ( byteCount > BulkMoveWithWriteBarrierChunk ) ;
196- }
197- else
198- {
199- // Copy backwards
200- do
201- {
202- byteCount -= BulkMoveWithWriteBarrierChunk ;
203- BulkMoveWithWriteBarrierInternal ( ref Unsafe . AddByteOffset ( ref destination , byteCount ) , ref Unsafe . AddByteOffset ( ref source , byteCount ) , BulkMoveWithWriteBarrierChunk ) ;
204- Thread . FastPollGC ( ) ;
205- }
206- while ( byteCount > BulkMoveWithWriteBarrierChunk ) ;
207- }
208- BulkMoveWithWriteBarrierInternal ( ref destination , ref source , byteCount ) ;
209- Thread . FastPollGC ( ) ;
66+ UnmanagedSpanHelpers . Memmove (
67+ ref Unsafe . As < T , byte > ( ref destination ) ,
68+ ref Unsafe . As < T , byte > ( ref source ) ,
69+ checked ( ( nuint ) ( elementCount * ( ulong ) sizeof ( T ) ) ) ) ;
21070 }
211-
212- #endif // !MONO
21371 }
21472}
0 commit comments