2020-05-02 17:54:07 +00:00
|
|
|
using System;
|
2020-05-03 15:14:07 +00:00
|
|
|
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
|
|
|
|
{
|
2020-07-25 10:52:18 +00:00
|
|
|
private IntPtr _ptr;
|
2020-05-19 12:25:21 +00:00
|
|
|
|
2020-05-04 15:35:53 +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-04 15:35:53 +00:00
|
|
|
}
|
2020-05-19 12:25:21 +00:00
|
|
|
|
2020-05-04 15:35:53 +00:00
|
|
|
return _ptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-02 18:30:33 +00:00
|
|
|
private bool _isDeleted = false;
|
2020-05-02 17:54:07 +00:00
|
|
|
|
2020-12-23 11:27:58 +00:00
|
|
|
private static readonly ConcurrentDictionary<IntPtr, WeakReference<PointerWrapper>> Cached =
|
|
|
|
new ConcurrentDictionary<IntPtr, WeakReference<PointerWrapper>>();
|
2020-05-03 15:14:07 +00:00
|
|
|
|
2020-05-19 12:25:21 +00:00
|
|
|
private protected PointerWrapper()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-05-02 17:54:07 +00:00
|
|
|
protected PointerWrapper(IntPtr ptr)
|
2020-07-25 10:52:18 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
{
|
2020-12-23 11:27:58 +00:00
|
|
|
if (ptr == IntPtr.Zero)
|
|
|
|
{
|
|
|
|
throw new NullReferenceException("Initializing pointer was nullptr");
|
|
|
|
}
|
2020-05-04 15:35:53 +00:00
|
|
|
_ptr = ptr;
|
2020-12-23 11:27:58 +00:00
|
|
|
var weakRef = new WeakReference<PointerWrapper>(this);
|
2020-05-19 12:25:21 +00:00
|
|
|
Cached.AddOrUpdate(ptr, weakRef, (intPtr, reference) => weakRef);
|
2020-05-03 15:14:07 +00:00
|
|
|
}
|
2020-05-19 12:25:21 +00:00
|
|
|
|
2020-05-19 11:14:05 +00:00
|
|
|
~PointerWrapper()
|
|
|
|
{
|
|
|
|
if (!_isDeleted)
|
|
|
|
Cached.TryRemove(Ptr, out _);
|
|
|
|
}
|
|
|
|
|
2020-08-08 12:32:27 +00:00
|
|
|
public static bool TryResolvePointer<T>(IntPtr p, out T? result) where T : PointerWrapper
|
2020-05-03 15:14:07 +00:00
|
|
|
{
|
2020-07-24 08:57:18 +00:00
|
|
|
if (p == IntPtr.Zero)
|
|
|
|
{
|
|
|
|
result = null;
|
|
|
|
return true;
|
|
|
|
}
|
2020-05-03 15:14:07 +00:00
|
|
|
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-03 15:14:07 +00:00
|
|
|
}
|
|
|
|
}
|
2020-05-19 12:25:21 +00:00
|
|
|
|
2020-05-03 15:14:07 +00:00
|
|
|
result = null;
|
|
|
|
return false;
|
2020-05-02 17:54:07 +00:00
|
|
|
}
|
|
|
|
|
2020-05-19 12:25:21 +00:00
|
|
|
|
2020-05-03 15:14:07 +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)
|
|
|
|
return;
|
|
|
|
DeletePtr();
|
2020-05-20 12:47:17 +00:00
|
|
|
MarkAsDeleted();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected internal virtual void MarkAsDeleted()
|
|
|
|
{
|
2020-05-02 17:54:07 +00:00
|
|
|
_isDeleted = true;
|
2020-05-20 12:47:17 +00:00
|
|
|
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();
|
|
|
|
}
|
2020-07-31 12:19:21 +00:00
|
|
|
|
|
|
|
public override string ToString()
|
|
|
|
{
|
|
|
|
return $"(#{_ptr}) -> {GetType().FullName}";
|
|
|
|
}
|
2020-05-02 17:54:07 +00:00
|
|
|
}
|
|
|
|
}
|