Initial commit
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace CeresSharp.Native;
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for unsafe code patterns and pointer operations.
|
||||
/// Provides utilities for array pinning and pointer conversions.
|
||||
/// </summary>
|
||||
internal static class UnsafeHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes an operation with a pinned array.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The unmanaged type of the array elements.</typeparam>
|
||||
/// <param name="array">The array to pin.</param>
|
||||
/// <param name="operation">The operation to execute with the pinned pointer.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when array is null.</exception>
|
||||
internal static void WithPinnedArray<T>(T[] array, Action<IntPtr> operation) where T : unmanaged
|
||||
{
|
||||
if (array == null)
|
||||
throw new ArgumentNullException(nameof(array));
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (T* ptr = array)
|
||||
{
|
||||
operation((IntPtr)ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes an operation with a pinned array and returns a result.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The unmanaged type of the array elements.</typeparam>
|
||||
/// <typeparam name="TResult">The return type.</typeparam>
|
||||
/// <param name="array">The array to pin.</param>
|
||||
/// <param name="operation">The operation to execute with the pinned pointer.</param>
|
||||
/// <returns>The result of the operation.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when array is null.</exception>
|
||||
internal static TResult WithPinnedArray<T, TResult>(T[] array, Func<IntPtr, TResult> operation) where T : unmanaged
|
||||
{
|
||||
if (array == null)
|
||||
throw new ArgumentNullException(nameof(array));
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (T* ptr = array)
|
||||
{
|
||||
return operation((IntPtr)ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes an operation with multiple pinned arrays.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The unmanaged type of the array elements.</typeparam>
|
||||
/// <param name="arrays">The arrays to pin.</param>
|
||||
/// <param name="operation">The operation to execute with the pinned pointers.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when arrays is null or contains null elements.</exception>
|
||||
internal static void WithPinnedArrays<T>(T[][] arrays, Action<IntPtr[]> operation) where T : unmanaged
|
||||
{
|
||||
if (arrays == null)
|
||||
throw new ArgumentNullException(nameof(arrays));
|
||||
|
||||
unsafe
|
||||
{
|
||||
var pointers = new IntPtr[arrays.Length];
|
||||
var pins = new GCHandle[arrays.Length];
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < arrays.Length; i++)
|
||||
{
|
||||
if (arrays[i] == null)
|
||||
throw new ArgumentException($"Array at index {i} is null", nameof(arrays));
|
||||
|
||||
pins[i] = GCHandle.Alloc(arrays[i], GCHandleType.Pinned);
|
||||
pointers[i] = pins[i].AddrOfPinnedObject();
|
||||
}
|
||||
|
||||
operation(pointers);
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var pin in pins)
|
||||
{
|
||||
if (pin.IsAllocated)
|
||||
pin.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pins an array and returns a GCHandle that must be freed by the caller.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The unmanaged type of the array elements.</typeparam>
|
||||
/// <param name="array">The array to pin.</param>
|
||||
/// <returns>A GCHandle that pins the array.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when array is null.</exception>
|
||||
internal static GCHandle PinArray<T>(T[] array) where T : unmanaged
|
||||
{
|
||||
if (array == null)
|
||||
throw new ArgumentNullException(nameof(array));
|
||||
|
||||
return GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies data from an IntPtr array to a managed array of arrays.
|
||||
/// </summary>
|
||||
/// <param name="parameterPtrs">Pointer to array of IntPtr pointers.</param>
|
||||
/// <param name="parameterBlockSizes">Array of sizes for each parameter block.</param>
|
||||
/// <returns>Array of parameter blocks.</returns>
|
||||
internal static double[][] CopyParameterBlocks(IntPtr parameterPtrs, int[] parameterBlockSizes)
|
||||
{
|
||||
if (parameterPtrs == IntPtr.Zero)
|
||||
throw new ArgumentException("Parameter pointers cannot be zero", nameof(parameterPtrs));
|
||||
if (parameterBlockSizes == null || parameterBlockSizes.Length == 0)
|
||||
throw new ArgumentException("Parameter block sizes cannot be null or empty", nameof(parameterBlockSizes));
|
||||
|
||||
var parameterBlocks = new double[parameterBlockSizes.Length][];
|
||||
|
||||
unsafe
|
||||
{
|
||||
var paramPtrs = (IntPtr*)parameterPtrs;
|
||||
for (int i = 0; i < parameterBlockSizes.Length; i++)
|
||||
{
|
||||
var size = parameterBlockSizes[i];
|
||||
if (size <= 0)
|
||||
throw new ArgumentException($"Parameter block size at index {i} must be positive", nameof(parameterBlockSizes));
|
||||
|
||||
parameterBlocks[i] = new double[size];
|
||||
Marshal.Copy(paramPtrs[i], parameterBlocks[i], 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
return parameterBlocks;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user