using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Ryujinx.Audio.Renderer.Utils { /// /// Helper for IO operations on and . /// public static class SpanIOHelper { /// /// Write the given data to the given backing and move cursor after the written data. /// /// The data type. /// The backing to store the data. /// The data to write to the backing . public static void Write(ref Memory backingMemory, ref T data) where T : unmanaged { int size = Unsafe.SizeOf(); if (size > backingMemory.Length) { throw new ArgumentOutOfRangeException(nameof(backingMemory), backingMemory.Length, null); } MemoryMarshal.Write(backingMemory.Span[..size], in data); backingMemory = backingMemory[size..]; } /// /// Write the given data to the given backing and move cursor after the written data. /// /// The data type. /// The backing to store the data. /// The data to write to the backing . public static void Write(ref Span backingMemory, ref T data) where T : unmanaged { int size = Unsafe.SizeOf(); if (size > backingMemory.Length) { throw new ArgumentOutOfRangeException(nameof(backingMemory), backingMemory.Length, null); } MemoryMarshal.Write(backingMemory[..size], in data); backingMemory = backingMemory[size..]; } /// /// Get a out of a and move cursor after T size. /// /// The data type. /// The backing to get a from. /// A from backing . public static Span GetWriteRef(ref Memory backingMemory) where T : unmanaged { int size = Unsafe.SizeOf(); if (size > backingMemory.Length) { throw new ArgumentOutOfRangeException(nameof(backingMemory), backingMemory.Length, null); } Span result = MemoryMarshal.Cast(backingMemory.Span[..size]); backingMemory = backingMemory[size..]; return result; } /// /// Get a out of a backingMemory and move cursor after T size. /// /// The data type. /// The backing to get a from. /// A from backing . public static Span GetWriteRef(ref Span backingMemory) where T : unmanaged { int size = Unsafe.SizeOf(); if (size > backingMemory.Length) { throw new ArgumentOutOfRangeException(nameof(backingMemory), backingMemory.Length, null); } Span result = MemoryMarshal.Cast(backingMemory[..size]); backingMemory = backingMemory[size..]; return result; } /// /// Read data from the given backing and move cursor after the read data. /// /// The data type. /// The backing to read data from. /// Return the read data. public static T Read(ref ReadOnlyMemory backingMemory) where T : unmanaged { int size = Unsafe.SizeOf(); if (size > backingMemory.Length) { throw new ArgumentOutOfRangeException(nameof(backingMemory), backingMemory.Length, null); } T result = MemoryMarshal.Read(backingMemory.Span[..size]); backingMemory = backingMemory[size..]; return result; } /// /// Read data from the given backing and move cursor after the read data. /// /// The data type. /// The backing to read data from. /// Return the read data. public static T Read(ref ReadOnlySpan backingMemory) where T : unmanaged { int size = Unsafe.SizeOf(); if (size > backingMemory.Length) { throw new ArgumentOutOfRangeException(nameof(backingMemory), backingMemory.Length, null); } T result = MemoryMarshal.Read(backingMemory[..size]); backingMemory = backingMemory[size..]; return result; } /// /// Extract a at the given index. /// /// The data type. /// The to extract the data from. /// The id in the provided memory. /// The max allowed count. (for bound checking of the id in debug mode) /// a at the given id. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Memory GetMemory(Memory memory, int id, uint count) where T : unmanaged { Debug.Assert(id >= 0 && id < count); return memory.Slice(id, 1); } /// /// Extract a ref T at the given index. /// /// The data type. /// The to extract the data from. /// The id in the provided memory. /// The max allowed count. (for bound checking of the id in debug mode) /// a ref T at the given id. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref T GetFromMemory(Memory memory, int id, uint count) where T : unmanaged { return ref GetMemory(memory, id, count).Span[0]; } } }