Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using JetBrains.Annotations;
- using System;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- namespace SpriteMaster.Extensions;
- internal static class ArrayExt {
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- private struct ArrayHeader {
- public nuint Type;
- public nuint Length;
- }
- [Pure, MustUseReturnValue, MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static unsafe ref ArrayHeader GetHeader<T>(T[] array) where T : struct {
- ref T element = ref MemoryMarshal.GetArrayDataReference(array);
- ref T headerOffset = ref Unsafe.SubtractByteOffset(ref element, (IntPtr)sizeof(ArrayHeader));
- return ref Unsafe.As<T, ArrayHeader>(ref headerOffset);
- }
- [Pure, MustUseReturnValue, MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static UIntPtr GetArrayType<T>() where T : struct {
- var refArray = Array.Empty<T>();
- return GetHeader(refArray).Type;
- }
- /// <summary>
- /// Converts the input array (<paramref name="source"/>)'s type and length to the requested destination type (<typeparamref name="TTo"/>).
- /// <para>
- /// Highly destructive and unsafe. <paramref name="source"/> must not be used after calling this.
- /// </para>
- /// </summary>
- /// <typeparam name="TFrom">Type to convert from.</typeparam>
- /// <typeparam name="TTo">Type to convert to.</typeparam>
- /// <param name="source"><seealso cref="Array"/> to convert.</param>
- /// <returns>The same array, but converted.</returns>
- [Pure, MustUseReturnValue, MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static TTo[] Convert<TFrom, TTo>(this TFrom[] source) where TFrom : struct where TTo : struct {
- if (typeof(TTo) == typeof(TFrom)) {
- return (TTo[])(object)source;
- }
- long byteLength = source.LongLength * Unsafe.SizeOf<TFrom>();
- (byteLength % Unsafe.SizeOf<TTo>()).AssertZero($"Invalid Array Conversion (misaligned sizes): {typeof(TFrom)} -> {typeof(TTo)}");
- long newLength = byteLength / Unsafe.SizeOf<TTo>();
- ref var header = ref GetHeader(source);
- header.Type = GetArrayType<TTo>();
- header.Length = (UIntPtr)newLength;
- return Unsafe.As<TFrom[], TTo[]>(ref source);
- }
- }
Add Comment
Please, Sign In to add comment