//
// Copyright (c) 2019-2021 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see .
//
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();
}
MemoryMarshal.Write(backingMemory.Span.Slice(0, size), ref data);
backingMemory = backingMemory.Slice(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();
}
MemoryMarshal.Write(backingMemory.Slice(0, size), ref data);
backingMemory = backingMemory.Slice(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();
}
Span result = MemoryMarshal.Cast(backingMemory.Span.Slice(0, size));
backingMemory = backingMemory.Slice(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();
}
Span result = MemoryMarshal.Cast(backingMemory.Slice(0, size));
backingMemory = backingMemory.Slice(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();
}
T result = MemoryMarshal.Read(backingMemory.Span.Slice(0, size));
backingMemory = backingMemory.Slice(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();
}
T result = MemoryMarshal.Read(backingMemory.Slice(0, size));
backingMemory = backingMemory.Slice(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];
}
}
}