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() { _ptr = IntPtr.Zero };
///
/// True if the pointer is null, false otherwise.
///
public readonly 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 readonly 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(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 readonly T* ToPointer() => (T*)_ptr;
public readonly override bool Equals(object obj)
{
return obj is ArrayPtr other && Equals(other);
}
public readonly bool Equals([AllowNull] ArrayPtr other)
{
return _ptr == other._ptr && Length == other.Length;
}
public readonly 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);
}
}
}