using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Ryujinx.Common.Memory { /// /// Represents an array of unmanaged resources. /// /// Array element type public unsafe struct ArrayPtr : IEquatable>, IArray where T : unmanaged { private IntPtr _ptr; /// /// Null pointer. /// public static ArrayPtr Null => new ArrayPtr() { _ptr = IntPtr.Zero }; /// /// True if the pointer is null, false otherwise. /// public bool IsNull => _ptr == IntPtr.Zero; /// /// Number of elements on the array. /// public int Length { get; } /// /// Gets a reference to the item at the given index. /// /// /// No bounds checks are performed, this allows negative indexing, /// but care must be taken if the index may be out of bounds. /// /// Index of the element /// Reference to the element at the given index public ref T this[int index] => ref Unsafe.AsRef((T*)_ptr + index); /// /// Creates a new array from a given reference. /// /// /// For data on the heap, proper pinning is necessary during /// use. Failure to do so will result in memory corruption and crashes. /// /// Reference of the first array element /// Number of elements on the array public ArrayPtr(ref T value, int length) { _ptr = (IntPtr)Unsafe.AsPointer(ref value); Length = length; } /// /// Creates a new array from a given pointer. /// /// Array base pointer /// Number of elements on the array public ArrayPtr(T* ptr, int length) { _ptr = (IntPtr)ptr; Length = length; } /// /// Creates a new array from a given pointer. /// /// Array base pointer /// Number of elements on the array public ArrayPtr(IntPtr ptr, int length) { _ptr = ptr; Length = length; } /// /// Splits the array starting at the specified position. /// /// Index where the new array should start /// New array starting at the specified position public ArrayPtr Slice(int start) => new ArrayPtr(ref this[start], Length - start); /// /// Gets a span from the array. /// /// Span of the array public Span AsSpan() => Length == 0 ? Span.Empty : MemoryMarshal.CreateSpan(ref this[0], Length); /// /// Gets the array base pointer. /// /// Base pointer public T* ToPointer() => (T*)_ptr; public override bool Equals(object obj) { return obj is ArrayPtr other && Equals(other); } public bool Equals([AllowNull] ArrayPtr other) { return _ptr == other._ptr && Length == other.Length; } public override int GetHashCode() { return HashCode.Combine(_ptr, Length); } public static bool operator ==(ArrayPtr left, ArrayPtr right) { return left.Equals(right); } public static bool operator !=(ArrayPtr left, ArrayPtr right) { return !(left == right); } } }