Ameisen

Untitled

Jun 18th, 2022
303
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 2.14 KB | None | 0 0
  1. using JetBrains.Annotations;
  2. using System;
  3. using System.Runtime.CompilerServices;
  4. using System.Runtime.InteropServices;
  5.  
  6. namespace SpriteMaster.Extensions;
  7.  
  8. internal static class ArrayExt {
  9.     [StructLayout(LayoutKind.Sequential, Pack = 1)]
  10.     private struct ArrayHeader {
  11.         public nuint Type;
  12.         public nuint Length;
  13.     }
  14.  
  15.     [Pure, MustUseReturnValue, MethodImpl(MethodImplOptions.AggressiveInlining)]
  16.     private static unsafe ref ArrayHeader GetHeader<T>(T[] array) where T : struct {
  17.         ref T element = ref MemoryMarshal.GetArrayDataReference(array);
  18.         ref T headerOffset = ref Unsafe.SubtractByteOffset(ref element, (IntPtr)sizeof(ArrayHeader));
  19.         return ref Unsafe.As<T, ArrayHeader>(ref headerOffset);
  20.     }
  21.  
  22.     [Pure, MustUseReturnValue, MethodImpl(MethodImplOptions.AggressiveInlining)]
  23.     private static UIntPtr GetArrayType<T>() where T : struct {
  24.         var refArray = Array.Empty<T>();
  25.         return GetHeader(refArray).Type;
  26.     }
  27.  
  28.     /// <summary>
  29.     /// Converts the input array (<paramref name="source"/>)'s type and length to the requested destination type (<typeparamref name="TTo"/>).
  30.     /// <para>
  31.     /// Highly destructive and unsafe. <paramref name="source"/> must not be used after calling this.
  32.     /// </para>
  33.     /// </summary>
  34.     /// <typeparam name="TFrom">Type to convert from.</typeparam>
  35.     /// <typeparam name="TTo">Type to convert to.</typeparam>
  36.     /// <param name="source"><seealso cref="Array"/> to convert.</param>
  37.     /// <returns>The same array, but converted.</returns>
  38.     [Pure, MustUseReturnValue, MethodImpl(MethodImplOptions.AggressiveInlining)]
  39.     internal static TTo[] Convert<TFrom, TTo>(this TFrom[] source) where TFrom : struct where TTo : struct {
  40.         if (typeof(TTo) == typeof(TFrom)) {
  41.             return (TTo[])(object)source;
  42.         }
  43.  
  44.         long byteLength = source.LongLength * Unsafe.SizeOf<TFrom>();
  45.  
  46.         (byteLength % Unsafe.SizeOf<TTo>()).AssertZero($"Invalid Array Conversion (misaligned sizes): {typeof(TFrom)} -> {typeof(TTo)}");
  47.  
  48.         long newLength = byteLength / Unsafe.SizeOf<TTo>();
  49.  
  50.         ref var header = ref GetHeader(source);
  51.         header.Type = GetArrayType<TTo>();
  52.         header.Length = (UIntPtr)newLength;
  53.  
  54.         return Unsafe.As<TFrom[], TTo[]>(ref source);
  55.     }
  56. }
  57.  
Add Comment
Please, Sign In to add comment