Initial commit

This commit is contained in:
2026-07-13 09:25:40 +07:00
parent c08ff54676
commit bccfb156d7
1938 changed files with 641646 additions and 0 deletions

View File

@@ -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;
}
}