using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; using Misaki.HighPerformance.LowLevel.Collections.Contracts; using System.Runtime.InteropServices; namespace Misaki.HighPerformance.LowLevel.Utilities; /// /// Provides extension methods for copying elements between unsafe collections and spans, converting collections to /// arrays or lists, and searching for values. /// public static unsafe class UnsafeCollectionExtensions { /// /// Copies elements from a source UnsafeCollection to a destination Span, ensuring both have the same size. /// /// The type of the destination collection, which must implement . /// Specifies the type of elements being copied, which must be unmanaged. /// Represents the source collection from which elements are copied. /// Represents the target span where elements are copied to. /// Thrown when the sizes of the source collection and destination span do not match. public static void CopyTo(this C source, Span destination) where C: IUnsafeCollection where T : unmanaged { if (source.Count > destination.Length) { throw new ArgumentException("Source collection is larger than the destination span."); } fixed (T* pDest = destination) { MemCpy(pDest, source.GetUnsafePtr(), (uint)(source.Count * sizeof(T))); } } /// /// Copies a range of elements from a source collection to a destination span, ensuring both are adequately sized. /// /// The type of the destination collection, which must implement . /// Specifies the type of elements being copied, which must be a value type. /// The collection from which elements are copied. /// The span where the elements will be copied to. /// The starting index in the source collection for the copy operation. /// The starting index in the destination span where the elements will be placed. /// The number of elements to copy from the source to the destination. /// Thrown when the specified range exceeds the bounds of the source collection or destination span. public static void CopyTo(this C source, Span destination, uint sourceIndex, uint destinationIndex, uint length) where C : IUnsafeCollection where T : unmanaged { if (sourceIndex + length > source.Count || destinationIndex + length > destination.Length) { throw new ArgumentException("Source collection or destination span is too small for the specified range."); } fixed (T* pDest = destination) { MemCpy(pDest + destinationIndex, (byte*)source.GetUnsafePtr() + sourceIndex * sizeof(T), (uint)(length * sizeof(T))); } } /// /// Copies elements from a source span to a destination unsafe collection, ensuring both have the same size. /// /// The type of the destination collection, which must implement . /// Specifies the type of elements being copied, which must be unmanaged. /// Represents the unsafe collection that will receive the copied elements. /// Represents the span containing the elements to be copied to the unsafe collection. /// Thrown when the source span and destination collection have different sizes. public static void CopyFrom(this C destination, ReadOnlySpan source) where C : IUnsafeCollection where T : unmanaged { if (destination.Count < source.Length) { throw new ArgumentException("Destination collection is smaller than the source span."); } fixed (T* pSrc = source) { MemCpy(destination.GetUnsafePtr(), pSrc, (uint)(source.Length * sizeof(T))); } } /// /// Copies a specified range of elements from a source span to a destination collection. /// /// The type of the destination collection, which must implement . /// Represents the type of elements being copied, which must be unmanaged. /// The collection where elements will be copied to. /// The span containing the elements to be copied. /// The starting index in the source span from which to begin copying. /// The starting index in the destination collection where the elements will be placed. /// The number of elements to copy from the source span to the destination collection. /// Thrown when the specified range exceeds the bounds of the source span or destination collection. public static void CopyFrom(this C destination, ReadOnlySpan source, uint sourceIndex, uint destinationIndex, uint length) where C : IUnsafeCollection where T : unmanaged { if (sourceIndex + length > source.Length || destinationIndex + length > destination.Count) { throw new ArgumentException("Source span or destination collection is too small for the specified range."); } fixed (T* pSrc = source) { MemCpy((byte*)destination.GetUnsafePtr() + destinationIndex * sizeof(T), pSrc + sourceIndex, (uint)(length * sizeof(T))); } } /// /// Converts a managed array to an UnsafeArray by copying its elements to unmanaged memory. /// /// The type of elements in the array, which must be unmanaged. /// The managed array to convert. /// The allocator to use for memory allocation of the UnsafeArray. /// A new UnsafeArray containing a copy of the source array elements. public static UnsafeArray ToUnsafeArray(this T[] source, Allocator allocator) where T : unmanaged { var array = new UnsafeArray(source.Length, allocator); fixed (T* pSrc = source) { MemCpy(array.GetUnsafePtr(), pSrc, (uint)(source.Length * sizeof(T))); } return array; } /// /// Converts a managed List to an UnsafeList by copying its elements to unmanaged memory. /// /// The type of elements in the list, which must be unmanaged. /// The managed List to convert. /// The allocator to use for memory allocation of the UnsafeList. /// A new UnsafeList containing a copy of the source list elements. public static UnsafeList ToUnsafeList(this List source, Allocator allocator) where T : unmanaged { var list = new UnsafeList(source.Count, allocator); fixed (T* pSrc = CollectionsMarshal.AsSpan(source)) { MemCpy(list.GetUnsafePtr(), pSrc, (uint)(source.Count * sizeof(T))); } return list; } /// /// Creates a new array containing all elements from the specified unsafe collection. /// /// The type of the source collection, which must implement . /// The type of elements contained in the collection. Must be an unmanaged type. /// The collection whose elements will be copied to the new array. Must not be null. /// An array containing all elements from in their current order. public static T[] ToArray(this C source) where C : IUnsafeCollection where T : unmanaged { return new Span(source.GetUnsafePtr(), source.Count).ToArray(); } /// /// Creates a new containing the elements of the specified unsafe collection. /// /// The type of the source collection, which must implement . /// The type of elements contained in the collection. Must be an unmanaged type. /// The unsafe collection whose elements are to be copied to the new list. Must not be null. /// A containing all elements from in their original order. public static List ToList(this C source) where C : IUnsafeCollection where T : unmanaged { var list = new List(source.Count); var span = new Span(source.GetUnsafePtr(), source.Count); span.CopyTo(CollectionsMarshal.AsSpan(list)); return list; } }