using System.Runtime.CompilerServices; namespace Dalamud.Bindings.ImGui; public unsafe struct ImVector { public readonly int Size; public readonly int Capacity; public readonly void* Data; public ImVector(int size, int capacity, void* data) { Size = size; Capacity = capacity; Data = data; } public ref T Ref(int index) { return ref Unsafe.AsRef((byte*)Data + index * Unsafe.SizeOf()); } public IntPtr Address(int index) { return (IntPtr)((byte*)Data + index * Unsafe.SizeOf()); } } /// /// A structure representing a dynamic array for unmanaged types. /// /// The type of elements in the vector, must be unmanaged. public unsafe struct ImVector where T : unmanaged { /// /// Initializes a new instance of the struct with the specified size, capacity, and data pointer. /// /// The initial size of the vector. /// The initial capacity of the vector. /// Pointer to the initial data. public ImVector(int size, int capacity, T* data) { this.size = size; this.capacity = capacity; this.data = data; } private int size; private int capacity; private unsafe T* data; /// /// Gets or sets the element at the specified index. /// /// The zero-based index of the element to get or set. /// The element at the specified index. /// Thrown when the index is out of range. public T this[int index] { get { if (index < 0 || index >= size) { throw new IndexOutOfRangeException(); } return data[index]; } set { if (index < 0 || index >= size) { throw new IndexOutOfRangeException(); } data[index] = value; } } /// /// Gets a pointer to the first element of the vector. /// public readonly T* Data => data; /// /// Gets a pointer to the first element of the vector. /// public readonly T* Front => data; /// /// Gets a pointer to the last element of the vector. /// public readonly T* Back => size > 0 ? data + size - 1 : null; /// /// Gets or sets the capacity of the vector. /// public int Capacity { readonly get => capacity; set { if (capacity == value) { return; } if (data == null) { data = (T*)ImGui.MemAlloc((nuint)(value * sizeof(T))); } else { int newSize = Math.Min(size, value); T* newData = (T*)ImGui.MemAlloc((nuint)(value * sizeof(T))); Buffer.MemoryCopy(data, newData, (nuint)(value * sizeof(T)), (nuint)(newSize * sizeof(T))); ImGui.MemFree(data); data = newData; size = newSize; } capacity = value; // Clear the rest of the data for (int i = size; i < capacity; i++) { data[i] = default; } } } /// /// Gets the number of elements in the vector. /// public readonly int Size => size; /// /// Grows the capacity of the vector to at least the specified value. /// /// The new capacity. public void Grow(int newCapacity) { if (newCapacity > capacity) { Capacity = newCapacity * 2; } } /// /// Ensures that the vector has at least the specified capacity. /// /// The minimum capacity required. public void EnsureCapacity(int size) { if (size > capacity) { Grow(size); } } /// /// Resizes the vector to the specified size. /// /// The new size of the vector. public void Resize(int newSize) { EnsureCapacity(newSize); size = newSize; } /// /// Clears all elements from the vector. /// public void Clear() { size = 0; } /// /// Adds an element to the end of the vector. /// /// The value to add. public void PushBack(T value) { EnsureCapacity(size + 1); data[size++] = value; } /// /// Removes the last element from the vector. /// public void PopBack() { if (size > 0) { size--; } } /// /// Frees the memory allocated for the vector. /// public void Free() { if (data != null) { ImGui.MemFree(data); data = null; size = 0; capacity = 0; } } public ref T Ref(int index) { return ref Unsafe.AsRef((byte*)Data + index * Unsafe.SizeOf()); } public ref TCast Ref(int index) { return ref Unsafe.AsRef((byte*)Data + index * Unsafe.SizeOf()); } public void* Address(int index) { return (byte*)Data + index * Unsafe.SizeOf(); } public void* Address(int index) { return (byte*)Data + index * Unsafe.SizeOf(); } public ImVector* ToUntyped() { return (ImVector*)Unsafe.AsPointer(ref this); } }