PkmnLibSharp/PkmnLibSharp/Utilities/ReadOnlyNativePtrArray.cs

118 lines
3.3 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
namespace PkmnLibSharp.Utilities
{
public class ReadOnlyNativePtrArray<T> : IReadOnlyList<T?> where T : PointerWrapper
{
private readonly IntPtr _ptr;
private readonly T?[] _cache;
private readonly Constructor.GenericType _constructorType;
internal ReadOnlyNativePtrArray(Constructor.GenericType type)
{
_ptr = IntPtr.Zero;
Count = 0;
_cache = new T[Count];
_constructorType = type;
}
internal ReadOnlyNativePtrArray(IntPtr ptr, int length, Constructor.GenericType type)
{
_ptr = ptr;
Count = length;
_cache = new T[Count];
_constructorType = type;
}
public IEnumerator<T?> GetEnumerator()
{
for (var i = 0; i < Count; i++)
{
yield return this[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public bool Contains(T item)
{
foreach (var v in this)
{
if (item == null && v == null)
{
return true;
}
if (v != null && item != null)
{
if (item.Ptr == v.Ptr)
return true;
}
}
return false;
}
public int Count { get; }
public int IndexOf(T? item)
{
for (var i = 0; i < Count; i++)
{
var p = _ptr + (i * IntPtr.Size);
if (item == null)
return i;
if (p == item.Ptr)
return i;
}
return -1;
}
private unsafe IntPtr GetPtr(int index)
{
if (index >= Count)
throw new IndexOutOfRangeException();
// Where's your god now?
// (We add the offset of the index to the pointer, then dereference the pointer pointer to get the actual pointer to the object we want.)
return new IntPtr(*(void**)IntPtr.Add(_ptr, index * IntPtr.Size).ToPointer());
}
internal T? GetDontInitialise(int index)
{
var p = GetPtr(index);
if (p == IntPtr.Zero)
return null;
lock (_cache)
{
if (_cache[index]?.Ptr == p)
return _cache[index]!;
}
if (PointerWrapper.TryResolvePointer(p, out T? t))
return t!;
return null;
}
public T? this[int index]
{
get
{
var p = GetPtr(index);
if (p == IntPtr.Zero)
return null;
lock (_cache)
{
if (_cache[index]?.Ptr == p)
return _cache[index]!;
if (PointerWrapper.TryResolvePointer(p, out T? t))
return t!;
t = (T?) Constructor.Active.InstantiateGeneric(_constructorType, p);
_cache[index] = t;
return t;
}
}
}
}
}