Initial commit
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user