#nullable disable
using System;
using System.Runtime.InteropServices;
namespace BizHawk.Common
{
///
/// Implements a data simple data buffer with proper life cycle and no bounds checking
///
public unsafe class CBuffer : IDisposable
{
public GCHandle Hnd;
public T[] Arr;
public void* Ptr;
public byte* Byteptr;
public int Len;
public int Itemsize;
public void Write08(int addr, byte val) { Byteptr[addr] = val; }
public void Write32(int addr, uint val) { *(uint*)(Byteptr + addr) = val; }
public byte Read08(int addr) { return Byteptr[addr]; }
public ushort Read16(int addr) { return *(ushort*)(Byteptr + addr); }
public uint Read32(int addr) { return *(uint*)(Byteptr + addr); }
public static CBuffer malloc(int amt, int itemsize)
{
return new CBuffer(amt, itemsize);
}
public CBuffer(T[] arr, int itemsize)
{
Itemsize = itemsize;
Len = arr.Length;
Arr = arr;
Hnd = GCHandle.Alloc(arr, GCHandleType.Pinned);
Ptr = Hnd.AddrOfPinnedObject().ToPointer();
Byteptr = (byte*)Ptr;
}
public CBuffer(int amt, int itemsize)
{
Itemsize = itemsize;
Len = amt;
Arr = new T[amt];
Hnd = GCHandle.Alloc(this.Arr, GCHandleType.Pinned);
Ptr = Hnd.AddrOfPinnedObject().ToPointer();
Byteptr = (byte*)Ptr;
Util.Memset(Byteptr, 0, Len * itemsize);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (Arr != null)
{
Hnd.Free();
}
Arr = null;
}
}
~CBuffer() { Dispose(true); }
}
public sealed class ByteBuffer : CBuffer
{
public ByteBuffer(int amt) : base(amt,1) { }
public ByteBuffer(byte[] arr) : base(arr,1) { }
public byte this[int index]
{
#if DEBUG
get => this.Arr[index];
set => this.Arr[index] = value;
#else
set => Write08(index, value);
get => Read08(index);
#endif
}
}
public sealed class IntBuffer : CBuffer
{
public IntBuffer(int amt) : base(amt, 4) { }
public IntBuffer(int[] arr) : base(arr,4) { }
public int this[int index]
{
#if DEBUG
get => this.Arr[index];
set => this.Arr[index] = value;
#else
set => Write32(index<<2, (uint) value);
get => (int)Read32(index<<2);
#endif
}
}
public sealed class ShortBuffer : CBuffer
{
public ShortBuffer(int amt) : base(amt, 2) { }
public ShortBuffer(short[] arr) : base(arr, 2) { }
public short this[int index]
{
#if DEBUG
get => this.Arr[index];
set => this.Arr[index] = value;
#else
set => Write32(index << 1, (uint)value);
get => (short)Read16(index << 1);
#endif
}
}
}