1
0
Fork 0
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:
Levi Broderick 2020-06-23 16:44:15 -07:00 committed by GitHub
parent 5eeaebc7aa
commit 09f1fa0e3d
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 13 deletions

View file

@ -51,7 +51,7 @@ namespace System
if (newSize < 0) if (newSize < 0)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.newSize, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.newSize, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
T[]? larray = array; T[]? larray = array; // local copy
if (larray == null) if (larray == null)
{ {
array = new T[newSize]; array = new T[newSize];
@ -60,8 +60,17 @@ namespace System
if (larray.Length != newSize) 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]; 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; array = newArray;
} }

View file

@ -31,29 +31,40 @@ namespace System.Runtime.CompilerServices
(int offset, int length) = range.GetOffsetAndLength(array.Length); (int offset, int length) = range.GetOffsetAndLength(array.Length);
T[] dest;
if (typeof(T).IsValueType || typeof(T[]) == array.GetType()) 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) if (length == 0)
{ {
return Array.Empty<T>(); return Array.Empty<T>();
} }
var dest = new T[length]; dest = new T[length];
Buffer.Memmove(
ref MemoryMarshal.GetArrayDataReference(dest),
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), offset),
(uint)length);
return dest;
} }
else else
{ {
// The array is actually a U[] where U:T. // The array is actually a U[] where U:T. We'll make sure to create
T[] dest = (T[])Array.CreateInstance(array.GetType().GetElementType()!, length); // an array of the exact same backing type. The cast to T[] will
Array.Copy(array, offset, dest, 0, length); // never fail.
return dest;
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( public static object GetUninitializedObject(