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,52 @@
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Base class for all Ceres native resource handles.
/// </summary>
public abstract class BaseSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
protected BaseSafeHandle() : base(true)
{
}
protected BaseSafeHandle(IntPtr handle, bool ownsHandle) : base(ownsHandle)
{
SetHandle(handle);
}
private volatile bool _released = false;
protected override bool ReleaseHandle()
{
// Prevent double-free by checking if already released
// Use volatile read/write for thread safety in finalizer
if (_released || IsInvalid)
return true; // Already released or invalid
try
{
// Add try-catch to prevent crash in finalizer thread
// If native handle is already freed or invalid, this will fail gracefully
ReleaseNativeHandle(handle);
_released = true;
return true;
}
catch
{
// Ignore errors in finalizer - native handle may already be freed
// Mark as released to prevent retry
_released = true;
// Return true to indicate handle was "released" (even if it failed)
return true;
}
}
/// <summary>
/// Releases the native handle. Must be implemented by derived classes.
/// </summary>
protected abstract void ReleaseNativeHandle(IntPtr handle);
}

View File

@@ -0,0 +1,33 @@
using System;
using CeresSharp.Native;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Safe handle for Ceres Context.
/// </summary>
internal sealed class ContextHandle : BaseSafeHandle
{
private ContextHandle() : base()
{
}
private ContextHandle(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle)
{
}
public static ContextHandle Create()
{
var handle = CeresNative.ceres_wrapper_create_context();
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.OutOfMemory, "Failed to create context");
}
return new ContextHandle(handle, true);
}
protected override void ReleaseNativeHandle(IntPtr handle)
{
CeresNative.ceres_wrapper_free_context(handle);
}
}

View File

@@ -0,0 +1,48 @@
using System;
using CeresSharp.Native;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Safe handle for Ceres CostFunction.
/// </summary>
internal sealed class CostFunctionHandle : BaseSafeHandle
{
private volatile bool _ownedByProblem = false;
private CostFunctionHandle() : base()
{
}
private CostFunctionHandle(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle)
{
}
public static CostFunctionHandle Create(IntPtr handle)
{
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.NullPointer, "Cost function handle is null");
}
return new CostFunctionHandle(handle, true);
}
/// <summary>
/// Marks this cost function as owned by a Problem.
/// When owned by Problem, the native handle should NOT be freed here
/// because Problem/Ceres will free it when Problem is destroyed.
/// </summary>
internal void MarkOwnedByProblem() => _ownedByProblem = true;
protected override void ReleaseNativeHandle(IntPtr handle)
{
if (_ownedByProblem)
{
// Problem owns this cost function - Ceres will delete it when Problem is freed.
// Do NOT free here to avoid double-free.
return;
}
// Standalone cost function - we must free it ourselves
CeresNative.ceres_wrapper_free_autodiff_cost_function(handle);
}
}

View File

@@ -0,0 +1,43 @@
using System;
using CeresSharp.Native;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Safe handle for Ceres Covariance.
/// </summary>
internal sealed class CovarianceHandle : BaseSafeHandle
{
private CovarianceHandle() : base()
{
}
private CovarianceHandle(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle)
{
}
public static CovarianceHandle Create()
{
var handle = CeresNative.ceres_wrapper_create_covariance();
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.OutOfMemory, "Failed to create covariance");
}
return new CovarianceHandle(handle, true);
}
public static CovarianceHandle CreateWithOptions(IntPtr options)
{
var handle = CeresNative.ceres_wrapper_create_covariance_with_options(options);
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.OutOfMemory, "Failed to create covariance with options");
}
return new CovarianceHandle(handle, true);
}
protected override void ReleaseNativeHandle(IntPtr handle)
{
CeresNative.ceres_wrapper_free_covariance(handle);
}
}

View File

@@ -0,0 +1,33 @@
using System;
using CeresSharp.Native;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Safe handle for Ceres CovarianceOptions.
/// </summary>
internal sealed class CovarianceOptionsHandle : BaseSafeHandle
{
private CovarianceOptionsHandle() : base()
{
}
private CovarianceOptionsHandle(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle)
{
}
public static CovarianceOptionsHandle Create()
{
var handle = CeresNative.ceres_wrapper_create_covariance_options();
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.OutOfMemory, "Failed to create covariance options");
}
return new CovarianceOptionsHandle(handle, true);
}
protected override void ReleaseNativeHandle(IntPtr handle)
{
CeresNative.ceres_wrapper_free_covariance_options(handle);
}
}

View File

@@ -0,0 +1,32 @@
using System;
using CeresSharp.Native;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Safe handle for Ceres GradientChecker.
/// </summary>
internal sealed class GradientCheckerHandle : BaseSafeHandle
{
private GradientCheckerHandle() : base()
{
}
private GradientCheckerHandle(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle)
{
}
public static GradientCheckerHandle Create(IntPtr handle)
{
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.NullPointer, "Gradient checker handle is null");
}
return new GradientCheckerHandle(handle, true);
}
protected override void ReleaseNativeHandle(IntPtr handle)
{
CeresNative.ceres_wrapper_free_gradient_checker(handle);
}
}

View File

@@ -0,0 +1,33 @@
using System;
using CeresSharp.Native;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Safe handle for Ceres GradientCheckerOptions.
/// </summary>
internal sealed class GradientCheckerOptionsHandle : BaseSafeHandle
{
private GradientCheckerOptionsHandle() : base()
{
}
private GradientCheckerOptionsHandle(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle)
{
}
public static GradientCheckerOptionsHandle Create()
{
var handle = CeresNative.ceres_wrapper_create_gradient_checker_options();
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.OutOfMemory, "Failed to create gradient checker options");
}
return new GradientCheckerOptionsHandle(handle, true);
}
protected override void ReleaseNativeHandle(IntPtr handle)
{
CeresNative.ceres_wrapper_free_gradient_checker_options(handle);
}
}

View File

@@ -0,0 +1,51 @@
using System;
using CeresSharp.Native;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Safe handle for Ceres Interpolator (BiCubic or Cubic).
/// </summary>
internal sealed class InterpolatorHandle : BaseSafeHandle
{
private readonly bool _isBicubic;
private InterpolatorHandle() : base()
{
}
private InterpolatorHandle(IntPtr handle, bool ownsHandle, bool isBicubic) : base(handle, ownsHandle)
{
_isBicubic = isBicubic;
}
public static InterpolatorHandle CreateBicubic(IntPtr handle)
{
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.NullPointer, "BiCubic interpolator handle is null");
}
return new InterpolatorHandle(handle, true, true);
}
public static InterpolatorHandle CreateCubic(IntPtr handle)
{
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.NullPointer, "Cubic interpolator handle is null");
}
return new InterpolatorHandle(handle, true, false);
}
protected override void ReleaseNativeHandle(IntPtr handle)
{
if (_isBicubic)
{
CeresNative.ceres_wrapper_free_bicubic_interpolator(handle);
}
else
{
CeresNative.ceres_wrapper_free_cubic_interpolator(handle);
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
using CeresSharp.Native;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Safe handle for Ceres LossFunction.
/// </summary>
internal sealed class LossFunctionHandle : BaseSafeHandle
{
private volatile bool _ownedByProblem = false;
private LossFunctionHandle() : base()
{
}
private LossFunctionHandle(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle)
{
}
public static LossFunctionHandle Create(IntPtr handle)
{
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.NullPointer, "Loss function handle is null");
}
return new LossFunctionHandle(handle, true);
}
/// <summary>
/// Marks this loss function as owned by a Problem.
/// When owned by Problem, the native handle should NOT be freed here
/// because Problem/Ceres will free it when Problem is destroyed.
/// </summary>
internal void MarkOwnedByProblem() => _ownedByProblem = true;
protected override void ReleaseNativeHandle(IntPtr handle)
{
if (_ownedByProblem)
{
// Problem owns this loss function - Ceres will delete it when Problem is freed.
// Do NOT free here to avoid double-free.
return;
}
// Standalone loss function - we must free it ourselves
CeresNative.ceres_wrapper_free_loss_function(handle);
}
}

View File

@@ -0,0 +1,32 @@
using System;
using CeresSharp.Native;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Safe handle for Ceres Manifold.
/// </summary>
internal sealed class ManifoldHandle : BaseSafeHandle
{
private ManifoldHandle() : base()
{
}
private ManifoldHandle(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle)
{
}
public static ManifoldHandle Create(IntPtr handle)
{
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.NullPointer, "Manifold handle is null");
}
return new ManifoldHandle(handle, true);
}
protected override void ReleaseNativeHandle(IntPtr handle)
{
CeresNative.ceres_wrapper_free_manifold(handle);
}
}

View File

@@ -0,0 +1,60 @@
using System;
using System.Runtime.InteropServices;
using CeresSharp.Native;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Safe handle for Ceres Problem.
/// Note: Uses official C API (ceres_create_problem/ceres_free_problem).
/// </summary>
internal sealed class ProblemHandle : BaseSafeHandle
{
private ProblemHandle() : base()
{
}
private ProblemHandle(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle)
{
}
public static ProblemHandle Create()
{
// Note: ceres_create_problem is from official C API, not wrapper
// We'll need to import it separately or use wrapper function if available
var handle = CeresNative.ceres_create_problem();
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.OutOfMemory, "Failed to create problem");
}
return new ProblemHandle(handle, true);
}
public static ProblemHandle CreateWithOptions(IntPtr problemOptions)
{
var handle = CeresNative.ceres_wrapper_create_problem_with_options(problemOptions);
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.OutOfMemory, "Failed to create problem with options");
}
return new ProblemHandle(handle, true);
}
protected override void ReleaseNativeHandle(IntPtr handle)
{
// Note: ceres_free_problem is from official C API
// Add null check to prevent crash if handle is invalid
if (handle != IntPtr.Zero)
{
try
{
CeresNative.ceres_free_problem(handle);
}
catch
{
// Ignore errors - handle may already be freed or invalid
// This can happen in finalizer thread
}
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using CeresSharp.Native;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Safe handle for Ceres ProblemOptions.
/// </summary>
internal sealed class ProblemOptionsHandle : BaseSafeHandle
{
private ProblemOptionsHandle() : base()
{
}
private ProblemOptionsHandle(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle)
{
}
public static ProblemOptionsHandle Create()
{
var handle = CeresNative.ceres_wrapper_create_problem_options();
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.OutOfMemory, "Failed to create problem options");
}
return new ProblemOptionsHandle(handle, true);
}
protected override void ReleaseNativeHandle(IntPtr handle)
{
CeresNative.ceres_wrapper_free_problem_options(handle);
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Runtime.InteropServices;
using CeresSharp.Native;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Safe handle for Ceres SolverOptions.
/// </summary>
internal sealed class SolverOptionsHandle : BaseSafeHandle
{
private SolverOptionsHandle() : base()
{
}
private SolverOptionsHandle(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle)
{
}
public static SolverOptionsHandle Create()
{
var handle = CeresNative.ceres_wrapper_create_solver_options();
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.OutOfMemory, "Failed to create solver options");
}
return new SolverOptionsHandle(handle, true);
}
protected override void ReleaseNativeHandle(IntPtr handle)
{
CeresNative.ceres_wrapper_free_solver_options(handle);
}
}

View File

@@ -0,0 +1,33 @@
using System;
using CeresSharp.Native;
namespace CeresSharp.Native.SafeHandles;
/// <summary>
/// Safe handle for Ceres SolverSummary.
/// </summary>
internal sealed class SolverSummaryHandle : BaseSafeHandle
{
private SolverSummaryHandle() : base()
{
}
internal SolverSummaryHandle(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle)
{
}
public static SolverSummaryHandle Create()
{
var handle = CeresNative.ceres_wrapper_create_solver_summary();
if (handle == IntPtr.Zero)
{
throw new Exceptions.CeresException(Exceptions.CeresErrorCode.OutOfMemory, "Failed to create solver summary");
}
return new SolverSummaryHandle(handle, true);
}
protected override void ReleaseNativeHandle(IntPtr handle)
{
CeresNative.ceres_wrapper_free_solver_summary(handle);
}
}