PkmnLibSharp/PkmnLibSharp/Utilities/PointerWrapper.cs

128 lines
3.3 KiB
C#
Raw Normal View History

2020-05-02 17:54:07 +00:00
using System;
using System.Collections.Concurrent;
2020-05-02 17:54:07 +00:00
2020-05-04 15:54:34 +00:00
namespace PkmnLibSharp.Utilities
2020-05-02 17:54:07 +00:00
{
public abstract class PointerWrapper : IDisposable
{
private IntPtr _ptr;
2020-05-19 12:25:21 +00:00
internal IntPtr Ptr
{
get
{
if (IsDeleted)
{
2020-05-19 12:25:21 +00:00
throw new Exception(
"Pointer access after dispose detected. This is not legal, and will cause native exceptions.");
}
2020-05-19 12:25:21 +00:00
return _ptr;
}
}
protected bool IsDeleted { get; private set; } = false;
2020-05-02 17:54:07 +00:00
private static readonly ConcurrentDictionary<IntPtr, WeakReference<PointerWrapper>> Cached =
new ConcurrentDictionary<IntPtr, WeakReference<PointerWrapper>>();
2020-05-19 12:25:21 +00:00
private protected PointerWrapper()
{
}
2020-05-02 17:54:07 +00:00
protected PointerWrapper(IntPtr ptr)
{
Initialize(ptr);
}
2020-07-25 13:23:01 +00:00
protected internal virtual void Initialize(IntPtr ptr)
2020-05-02 17:54:07 +00:00
{
if (ptr == IntPtr.Zero)
{
throw new NullReferenceException("Initializing pointer was nullptr");
}
_ptr = ptr;
var weakRef = new WeakReference<PointerWrapper>(this);
2020-05-19 12:25:21 +00:00
Cached.AddOrUpdate(ptr, weakRef, (intPtr, reference) => weakRef);
}
2020-05-19 12:25:21 +00:00
~PointerWrapper()
{
if (!IsDeleted)
Cached.TryRemove(Ptr, out _);
}
public static bool TryResolvePointer<T>(IntPtr p, out T? result) where T : PointerWrapper
{
2020-07-24 08:57:18 +00:00
if (p == IntPtr.Zero)
{
result = null;
return true;
}
if (Cached.TryGetValue(p, out var val))
{
if (val.TryGetTarget(out var target))
{
2020-05-19 12:25:21 +00:00
if (target is T r)
{
result = r;
return true;
}
}
}
2020-05-19 12:25:21 +00:00
result = null;
return false;
2020-05-02 17:54:07 +00:00
}
2020-05-19 12:25:21 +00:00
protected abstract void DeletePtr();
2020-05-19 12:25:21 +00:00
2020-05-02 17:54:07 +00:00
public virtual void Dispose()
{
if (IsDeleted)
2020-05-02 17:54:07 +00:00
return;
DeletePtr();
MarkAsDeleted();
}
protected internal virtual void MarkAsDeleted()
{
IsDeleted = true;
Cached.TryRemove(_ptr, out _);
2020-05-02 17:54:07 +00:00
}
2020-05-19 12:25:21 +00:00
2020-08-10 17:13:17 +00:00
public static bool operator ==(PointerWrapper? a, PointerWrapper? b)
{
return a?._ptr == b?._ptr;
}
public static bool operator !=(PointerWrapper? a, PointerWrapper? b)
{
return !(a == b);
}
2020-05-19 12:25:21 +00:00
protected bool Equals(PointerWrapper other)
{
return _ptr.Equals(other._ptr);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((PointerWrapper) obj);
}
public override int GetHashCode()
{
return _ptr.GetHashCode();
}
public override string ToString()
{
return $"(#{_ptr}) -> {GetType().FullName}";
}
2020-05-02 17:54:07 +00:00
}
}