118 lines
3.3 KiB
C#
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 = GetPtr(i);
|
|
if (item == null && p == IntPtr.Zero)
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |