using System; using System.Collections; using System.Collections.Generic; namespace PkmnLibSharp.Utilities { public class ReadOnlyNativePtrArray : IReadOnlyList 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 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; } } } } }