mirror of
https://github.com/VSadov/Satori.git
synced 2025-06-09 17:44:48 +09:00
Prefer Buffer.Memmove over Array.Copy in some scenarios (#35733)
This commit is contained in:
parent
5eeaebc7aa
commit
09f1fa0e3d
2 changed files with 33 additions and 13 deletions
|
@ -51,7 +51,7 @@ namespace System
|
|||
if (newSize < 0)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.newSize, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
|
||||
|
||||
T[]? larray = array;
|
||||
T[]? larray = array; // local copy
|
||||
if (larray == null)
|
||||
{
|
||||
array = new T[newSize];
|
||||
|
@ -60,8 +60,17 @@ namespace System
|
|||
|
||||
if (larray.Length != newSize)
|
||||
{
|
||||
// Due to array variance, it's possible that the incoming array is
|
||||
// actually of type U[], where U:T; or that an int[] <-> uint[] or
|
||||
// similar cast has occurred. In any case, since it's always legal
|
||||
// to reinterpret U as T in this scenario (but not necessarily the
|
||||
// other way around), we can use Buffer.Memmove here.
|
||||
|
||||
T[] newArray = new T[newSize];
|
||||
Copy(larray, 0, newArray, 0, larray.Length > newSize ? newSize : larray.Length);
|
||||
Buffer.Memmove<T>(
|
||||
ref MemoryMarshal.GetArrayDataReference(newArray),
|
||||
ref MemoryMarshal.GetArrayDataReference(larray),
|
||||
(uint)Math.Min(newSize, larray.Length));
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,29 +31,40 @@ namespace System.Runtime.CompilerServices
|
|||
|
||||
(int offset, int length) = range.GetOffsetAndLength(array.Length);
|
||||
|
||||
T[] dest;
|
||||
|
||||
if (typeof(T).IsValueType || typeof(T[]) == array.GetType())
|
||||
{
|
||||
// We know the type of the array to be exactly T[].
|
||||
// We know the type of the array to be exactly T[] or an array variance
|
||||
// compatible value type substitution like int[] <-> uint[].
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return Array.Empty<T>();
|
||||
}
|
||||
|
||||
var dest = new T[length];
|
||||
Buffer.Memmove(
|
||||
ref MemoryMarshal.GetArrayDataReference(dest),
|
||||
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), offset),
|
||||
(uint)length);
|
||||
return dest;
|
||||
dest = new T[length];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The array is actually a U[] where U:T.
|
||||
T[] dest = (T[])Array.CreateInstance(array.GetType().GetElementType()!, length);
|
||||
Array.Copy(array, offset, dest, 0, length);
|
||||
return dest;
|
||||
// The array is actually a U[] where U:T. We'll make sure to create
|
||||
// an array of the exact same backing type. The cast to T[] will
|
||||
// never fail.
|
||||
|
||||
dest = Unsafe.As<T[]>(Array.CreateInstance(array.GetType().GetElementType()!, length));
|
||||
}
|
||||
|
||||
// In either case, the newly-allocated array is the exact same type as the
|
||||
// original incoming array. It's safe for us to Buffer.Memmove the contents
|
||||
// from the source array to the destination array, otherwise the contents
|
||||
// wouldn't have been valid for the source array in the first place.
|
||||
|
||||
Buffer.Memmove(
|
||||
ref MemoryMarshal.GetArrayDataReference(dest),
|
||||
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), offset),
|
||||
(uint)length);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
public static object GetUninitializedObject(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue