// Copyright (c) 2021 homuler // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. using System; using System.Runtime.InteropServices; namespace Mediapipe { public abstract class MpResourceHandle : DisposableObject, IMpResourceHandle { private IntPtr _ptr = IntPtr.Zero; protected IntPtr ptr { get => _ptr; set { if (value != IntPtr.Zero && OwnsResource()) { throw new InvalidOperationException($"This object owns another resource"); } _ptr = value; } } protected MpResourceHandle(bool isOwner = true) : this(IntPtr.Zero, isOwner) { } protected MpResourceHandle(IntPtr ptr, bool isOwner = true) : base(isOwner) { this.ptr = ptr; } #region IMpResourceHandle public IntPtr mpPtr { get { ThrowIfDisposed(); return ptr; } } public void ReleaseMpResource() { if (OwnsResource()) { DeleteMpPtr(); } ReleaseMpPtr(); TransferOwnership(); } public bool OwnsResource() { return isOwner && IsResourcePresent(); } #endregion protected override void DisposeUnmanaged() { if (OwnsResource()) { DeleteMpPtr(); } ReleaseMpPtr(); base.DisposeUnmanaged(); } /// /// Forgets the pointer address. /// After calling this method, will return false. /// protected void ReleaseMpPtr() { ptr = IntPtr.Zero; } /// /// Release the memory (call `delete` or `delete[]`) whether or not it owns it. /// /// In most cases, this method should not be called directly protected abstract void DeleteMpPtr(); protected delegate MpReturnCode StringOutFunc(IntPtr ptr, out IntPtr strPtr); protected string MarshalStringFromNative(StringOutFunc f) { f(mpPtr, out var strPtr).Assert(); GC.KeepAlive(this); var str = Marshal.PtrToStringAnsi(strPtr); UnsafeNativeMethods.delete_array__PKc(strPtr); return str; } protected bool IsResourcePresent() { return ptr != IntPtr.Zero; } } }