Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/Array.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public static void Resize<T>([NotNull] ref T[]? array, int newSize)
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];
Expand All @@ -60,8 +60,17 @@ public static void Resize<T>([NotNull] ref T[]? array, int 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];
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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,40 @@ public static T[] GetSubArray<T>(T[] array, Range range)

(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(Type type)
Expand Down