Skip to content

Instantly share code, notes, and snippets.

@thatcosmonaut
Last active June 19, 2023 22:25
Show Gist options
  • Save thatcosmonaut/5ecb4bf6b519d068d50fd4e526757968 to your computer and use it in GitHub Desktop.
Save thatcosmonaut/5ecb4bf6b519d068d50fd4e526757968 to your computer and use it in GitHub Desktop.
DPBuffer
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using dp.type;
namespace SamuraiGunn2
{
public unsafe class DPBuffer : IBuffer, IDisposable
{
private byte* Bytes;
private int Length;
private int Position;
private bool disposed;
public DPBuffer(int length)
{
Bytes = (byte*) NativeMemory.Alloc((nuint) length);
Length = length;
}
public int Crc32(int offset, int len)
{
// Algorithm taken from K&R C 2nd edition
var hashval = 0;
for (var i = offset; i < len; i += 1)
{
hashval = Bytes[i] + 31 * hashval;
}
return hashval;
}
public Span<byte> GetBytes()
{
return new Span<byte>(Bytes, Length);
}
public int GetSize()
{
return Length;
}
public int PeekByteUnsigned(int pos)
{
return (int) Bytes[pos];
}
public int PeekInt(int pos)
{
return Unsafe.Read<int>(Bytes + pos);
}
public long PeekInt64(int pos)
{
return Unsafe.Read<long>(Bytes + pos);
}
public int PeekShortUnsigned(int pos)
{
return Unsafe.Read<ushort>(Bytes + pos);
}
public void PokeInt(int pos, int s32)
{
Unsafe.Write<int>(Bytes + pos, s32);
}
public void PokeInt64(int pos, long s64)
{
Unsafe.Write<long>(Bytes + pos, s64);
}
public void PokeShortUnsigned(int pos, int u16)
{
Unsafe.Write<ushort>(Bytes + pos, (ushort) u16);
}
public bool ReadBool()
{
var b = Unsafe.Read<byte>(Bytes + Position) != 0;
Position += 1;
return b;
}
public int ReadByteSigned()
{
var b = (sbyte) Bytes[Position];
Position += 1;
return b;
}
public int ReadByteUnsigned()
{
var b = Bytes[Position];
Position += 1;
return b;
}
public string ReadCString()
{
byte c = Bytes[Position];
var len = 1;
while (c != 0)
{
c = Bytes[Position + len];
len += 1;
}
return System.Text.Encoding.UTF8.GetString(new ReadOnlySpan<byte>(Bytes + Position, len));
}
public int ReadInt()
{
var i = Unsafe.Read<int>(Bytes + Position);
Position += 4;
return i;
}
public long ReadInt64()
{
var i = Unsafe.Read<long>(Bytes + Position);
Position += 8;
return i;
}
public int ReadShortSigned()
{
var s = Unsafe.Read<short>(Bytes + Position);
Position += 2;
return s;
}
public int ReadShortUnsigned()
{
var s = Unsafe.Read<ushort>(Bytes + Position);
Position += 2;
return s;
}
public void Resize(int newSize)
{
if (newSize > Length)
{
Bytes = (byte*) NativeMemory.Realloc(Bytes, (nuint) newSize);
Length = newSize;
}
}
public void Rewind()
{
Position = 0;
}
public void SavePart(string fname, int offset, int len)
{
using var filestream = new FileStream(fname, FileMode.Create, FileAccess.Write);
filestream.Write(new ReadOnlySpan<byte>(Bytes + offset, len));
}
public void SeekRelative(int positionOffset)
{
Position += positionOffset;
}
public void SeekStart(int newPosition)
{
Position = newPosition;
}
public void SetToBytes(Span<byte> bytes)
{
var span = new Span<byte>(Bytes, Length);
bytes.CopyTo(span);
}
public int Tell()
{
return Position;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CheckResize(int elementSize)
{
if (Position + elementSize >= Length)
{
Resize(Length * 2);
}
}
public void WriteBool(bool b)
{
CheckResize(1);
Unsafe.Write<byte>(Bytes + Position, b ? (byte) 1 : (byte) 0);
Position += 1;
}
public void WriteByteSigned(int s8)
{
CheckResize(1);
Unsafe.Write<sbyte>(Bytes + Position, (sbyte) s8);
Position += 1;
}
public void WriteByteUnsigned(int u8)
{
CheckResize(1);
Unsafe.Write<byte>(Bytes + Position, (byte) u8);
Position += 1;
}
public void WriteChars(string s)
{
var span = new Span<byte>(Bytes + Position, Length - Position);
var len = System.Text.Encoding.UTF8.GetBytes(s.AsSpan(), span);
Position += len;
}
public void WriteCString(string s)
{
WriteChars(s);
Unsafe.Write<byte>(Bytes + Position, 0);
Position += 1;
}
public void WriteInt(int s32)
{
CheckResize(4);
Unsafe.Write<int>(Bytes + Position, s32);
Position += 4;
}
public void WriteInt64(long s64)
{
CheckResize(8);
Unsafe.Write<long>(Bytes + Position, s64);
Position += 8;
}
public void WriteShortSigned(int s16)
{
CheckResize(2);
Unsafe.Write<short>(Bytes + Position, (short) s16);
Position += 2;
}
public void WriteShortUnsigned(int u16)
{
CheckResize(2);
Unsafe.Write<ushort>(Bytes + Position, (ushort) u16);
Position += 2;
}
void IBuffer.CopyFrom<T>(int dest, T src, int srcPos, int len)
{
var destSpan = new Span<byte>(Bytes + dest, Length - dest);
var srcSpan = src.GetBytes().Slice(srcPos, len);
srcSpan.CopyTo(destSpan);
}
void IBuffer.ReadBuffer<T>(T dest, int dstPos, int len)
{
var destSpan = dest.GetBytes().Slice(dstPos);
var srcSpan = new Span<byte>(Bytes + Position, len);
srcSpan.CopyTo(destSpan);
}
void IBuffer.WriteBufferExt<T>(T src, int srcPos, int len)
{
CheckResize(len);
var srcSpan = src.GetBytes().Slice(srcPos, len);
var destSpan = new Span<byte>(Bytes + Position, Length - Position);
srcSpan.CopyTo(destSpan);
Position += len;
}
protected virtual void Dispose(bool disposing)
{
if (disposed)
{
return;
}
if (disposing)
{
// dispose managed state (managed objects).
}
NativeMemory.Free(Bytes);
Bytes = null;
disposed = true;
}
~DPBuffer()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: false);
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment