/ src / Ryujinx.Common / Memory / ArrayPtr.cs
ArrayPtr.cs
  1  using System;
  2  using System.Diagnostics.CodeAnalysis;
  3  using System.Runtime.CompilerServices;
  4  using System.Runtime.InteropServices;
  5  
  6  namespace Ryujinx.Common.Memory
  7  {
  8      /// <summary>
  9      /// Represents an array of unmanaged resources.
 10      /// </summary>
 11      /// <typeparam name="T">Array element type</typeparam>
 12      public unsafe struct ArrayPtr<T> : IEquatable<ArrayPtr<T>>, IArray<T> where T : unmanaged
 13      {
 14          private IntPtr _ptr;
 15  
 16          /// <summary>
 17          /// Null pointer.
 18          /// </summary>
 19          public static ArrayPtr<T> Null => new() { _ptr = IntPtr.Zero };
 20  
 21          /// <summary>
 22          /// True if the pointer is null, false otherwise.
 23          /// </summary>
 24          public readonly bool IsNull => _ptr == IntPtr.Zero;
 25  
 26          /// <summary>
 27          /// Number of elements on the array.
 28          /// </summary>
 29          public int Length { get; }
 30  
 31          /// <summary>
 32          /// Gets a reference to the item at the given index.
 33          /// </summary>
 34          /// <remarks>
 35          /// No bounds checks are performed, this allows negative indexing,
 36          /// but care must be taken if the index may be out of bounds.
 37          /// </remarks>
 38          /// <param name="index">Index of the element</param>
 39          /// <returns>Reference to the element at the given index</returns>
 40          public readonly ref T this[int index] => ref Unsafe.AsRef<T>((T*)_ptr + index);
 41  
 42          /// <summary>
 43          /// Creates a new array from a given reference.
 44          /// </summary>
 45          /// <remarks>
 46          /// For data on the heap, proper pinning is necessary during
 47          /// use. Failure to do so will result in memory corruption and crashes.
 48          /// </remarks>
 49          /// <param name="value">Reference of the first array element</param>
 50          /// <param name="length">Number of elements on the array</param>
 51          public ArrayPtr(ref T value, int length)
 52          {
 53              _ptr = (IntPtr)Unsafe.AsPointer(ref value);
 54              Length = length;
 55          }
 56  
 57          /// <summary>
 58          /// Creates a new array from a given pointer.
 59          /// </summary>
 60          /// <param name="ptr">Array base pointer</param>
 61          /// <param name="length">Number of elements on the array</param>
 62          public ArrayPtr(T* ptr, int length)
 63          {
 64              _ptr = (IntPtr)ptr;
 65              Length = length;
 66          }
 67  
 68          /// <summary>
 69          /// Creates a new array from a given pointer.
 70          /// </summary>
 71          /// <param name="ptr">Array base pointer</param>
 72          /// <param name="length">Number of elements on the array</param>
 73          public ArrayPtr(IntPtr ptr, int length)
 74          {
 75              _ptr = ptr;
 76              Length = length;
 77          }
 78  
 79          /// <summary>
 80          /// Splits the array starting at the specified position.
 81          /// </summary>
 82          /// <param name="start">Index where the new array should start</param>
 83          /// <returns>New array starting at the specified position</returns>
 84          public ArrayPtr<T> Slice(int start) => new(ref this[start], Length - start);
 85  
 86          /// <summary>
 87          /// Gets a span from the array.
 88          /// </summary>
 89          /// <returns>Span of the array</returns>
 90          public Span<T> AsSpan() => Length == 0 ? Span<T>.Empty : MemoryMarshal.CreateSpan(ref this[0], Length);
 91  
 92          /// <summary>
 93          /// Gets the array base pointer.
 94          /// </summary>
 95          /// <returns>Base pointer</returns>
 96          public readonly T* ToPointer() => (T*)_ptr;
 97  
 98          public readonly override bool Equals(object obj)
 99          {
100              return obj is ArrayPtr<T> other && Equals(other);
101          }
102  
103          public readonly bool Equals([AllowNull] ArrayPtr<T> other)
104          {
105              return _ptr == other._ptr && Length == other.Length;
106          }
107  
108          public readonly override int GetHashCode()
109          {
110              return HashCode.Combine(_ptr, Length);
111          }
112  
113          public static bool operator ==(ArrayPtr<T> left, ArrayPtr<T> right)
114          {
115              return left.Equals(right);
116          }
117  
118          public static bool operator !=(ArrayPtr<T> left, ArrayPtr<T> right)
119          {
120              return !(left == right);
121          }
122      }
123  }