using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
using Misaki.HighPerformance.LowLevel.Collections.Contracts;
using System.Runtime.InteropServices;
namespace Misaki.HighPerformance.LowLevel.Helpers;
///
/// Provides extension methods for copying elements between unsafe collections and spans, converting collections to
/// arrays or lists, and searching for values.
///
public unsafe static class UnsafeCollectionExtensions
{
///
/// Copies elements from a source UnsafeCollection to a destination Span, ensuring both have the same size.
///
/// 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 IUnsafeCollection source, Span destination)
where T : unmanaged
{
if (source.Count > destination.Length)
{
throw new ArgumentException("Source collection is larger than the destination span.");
}
fixed (T* pDest = destination)
{
MemCpy(source.GetUnsafePtr(), pDest, (uint)(source.Count * sizeof(T)));
}
}
///
/// Copies a range of elements from a source collection to a destination span, ensuring both are adequately sized.
///
/// 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 IUnsafeCollection source, Span destination, uint sourceIndex, uint destinationIndex, uint length)
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((byte*)source.GetUnsafePtr() + sourceIndex * sizeof(T), pDest + destinationIndex, (uint)(length * sizeof(T)));
}
}
///
/// Copies elements from an untyped source collection to a destination span of a specific type.
///
/// Specifies the type of elements in the destination span, which must be unmanaged.
/// The untyped collection from which data is copied.
/// The typed span where the data will be copied to.
/// Thrown when the source collection size exceeds the destination span capacity.
public static void CopyTo(this IUnTypedCollection source, Span destination)
where T : unmanaged
{
var destSize = (uint)destination.Length * (uint)sizeof(T);
if (source.Size > destSize)
{
throw new ArgumentException("Source collection is larger than the destination span.");
}
fixed (T* pDest = destination)
{
MemCpy(source.GetUnsafePtr(), pDest, source.Size);
}
}
///
/// Copies a range of bytes from an untyped source collection to a destination span, interpreting the bytes as elements of type T.
///
/// Specifies the type of elements in the destination span, which must be unmanaged.
/// The untyped collection from which bytes are copied.
/// The typed span where the elements will be placed.
/// The byte offset in the source collection from which to start copying.
/// The element index in the destination span where copying will begin.
/// The number of elements of type T to copy.
/// Thrown when the specified range exceeds the bounds of the source collection or destination span.
public static void CopyTo(this IUnTypedCollection source, Span destination, uint sourceOffset, uint destinationIndex, uint length)
where T : unmanaged
{
var sizeOfElement = (uint)sizeof(T);
if (sourceOffset + (length * sizeOfElement) > source.Size || destinationIndex + length > destination.Length)
{
throw new ArgumentException("Source collection or destination span is too small for the specified range.");
}
fixed (T* pDest = destination)
{
MemCpy((byte*)source.GetUnsafePtr() + sourceOffset, pDest + destinationIndex, length * sizeOfElement);
}
}
///
/// Copies elements from a source span to a destination unsafe collection, ensuring both have the same size.
///
/// 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 IUnsafeCollection destination, ReadOnlySpan source)
where T : unmanaged
{
if (destination.Count < source.Length)
{
throw new ArgumentException("Destination collection is smaller than the source span.");
}
fixed (T* pSrc = source)
{
MemCpy(pSrc, destination.GetUnsafePtr(), (uint)(source.Length * sizeof(T)));
}
}
///
/// Copies a specified range of elements from a source span to a destination collection.
///
/// 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 IUnsafeCollection destination, ReadOnlySpan source, uint sourceIndex, uint destinationIndex, uint length)
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(pSrc + sourceIndex, (byte*)destination.GetUnsafePtr() + destinationIndex * sizeof(T), (uint)(length * sizeof(T)));
}
}
///
/// Copies elements from a typed source span to an untyped destination collection.
///
/// Specifies the type of elements in the source span, which must be unmanaged.
/// The untyped collection that will receive the copied data.
/// The typed span containing the elements to be copied.
/// Thrown when the destination collection is smaller than the source span data size.
public static void CopyFrom(this IUnTypedCollection destination, ReadOnlySpan source)
where T : unmanaged
{
var sourceSize = (uint)(source.Length * sizeof(T));
if (destination.Size < sourceSize)
{
throw new ArgumentException("Destination collection is smaller than the source span.");
}
fixed (T* pSrc = source)
{
MemCpy(pSrc, destination.GetUnsafePtr(), sourceSize);
}
}
///
/// Copies a range of elements from a typed source span to an untyped destination collection at a specified byte offset.
///
/// Specifies the type of elements in the source span, which must be unmanaged.
/// The untyped collection where the data will be copied to.
/// The typed span containing the elements to be copied.
/// The starting element index in the source span from which to begin copying.
/// The byte offset in the destination collection where the data will be placed.
/// The number of elements to copy from the source span.
/// Thrown when the specified range exceeds the bounds of the source span or destination collection.
public static void CopyFrom(this IUnTypedCollection destination, ReadOnlySpan source, uint sourceIndex, uint destinationOffset, uint length)
where T : unmanaged
{
var sizeOfElement = (uint)sizeof(T);
if (sourceIndex + length > source.Length || destinationOffset + (length * sizeOfElement) > destination.Size)
{
throw new ArgumentException("Source span or destination collection is too small for the specified range.");
}
fixed (T* pSrc = source)
{
MemCpy(pSrc + sourceIndex, (byte*)destination.GetUnsafePtr() + destinationOffset, length * sizeOfElement);
}
}
///
/// Converts an UnsafeCollection into a Span for efficient memory access.
///
/// Represents a type that can be stored in unmanaged memory.
/// The UnsafeCollection instance to be converted into a Span.
/// A Span that provides a view over the elements of the UnsafeCollection.
public static Span AsSpan(this IUnsafeCollection source)
where T : unmanaged
{
return new(source.GetUnsafePtr(), source.Count);
}
///
/// Converts an UnTypedCollection into a Span for efficient memory access.
///
/// The UnTypedCollection instance to be converted into a Span.
/// A Span that provides a view over the elements of the UnsafeCollection.
public static Span AsSpan(this IUnTypedCollection source)
{
return new(source.GetUnsafePtr(), (int)source.Size);
}
///
/// 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(pSrc, array.GetUnsafePtr(), (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(pSrc, list.GetUnsafePtr(), (uint)(source.Count * sizeof(T)));
}
return list;
}
}