1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 12:32:20 +02:00

Stream buffering

This commit is contained in:
Brian Fiete 2021-04-11 07:04:17 -04:00
parent 2345d5d349
commit 4bf12e121c
11 changed files with 482 additions and 28 deletions

View file

@ -215,10 +215,19 @@ namespace System
{
T mFirstElement;
public T* Ptr
{
[Inline]
get
{
return &mFirstElement;
}
}
public this()
{
}
[Inline]
ref T GetRef(int idx)
{
@ -330,6 +339,15 @@ namespace System
int_arsize mLength1;
T mFirstElement;
public T* Ptr
{
[Inline]
get
{
return &mFirstElement;
}
}
Array GetSelf()
{
return this;
@ -338,7 +356,7 @@ namespace System
public this()
{
}
public int GetLength(int dim)
{
if (dim == 0)
@ -447,6 +465,15 @@ namespace System
int_arsize mLength2;
T mFirstElement;
public T* Ptr
{
[Inline]
get
{
return &mFirstElement;
}
}
Array GetSelf()
{
return this;
@ -569,6 +596,15 @@ namespace System
int_arsize mLength3;
T mFirstElement;
public T* Ptr
{
[Inline]
get
{
return &mFirstElement;
}
}
Array GetSelf()
{
return this;

View file

@ -0,0 +1,183 @@
namespace System.IO
{
abstract class BufferedStream : Stream
{
protected int64 mPos;
protected int64 mUnderlyingLength;
protected uint8[] mBuffer ~ delete _;
protected int64 mBufferPos = -Int32.MinValue;
protected int64 mBufferEnd = -Int32.MinValue;
protected int64 mWriteDirtyPos = -Int32.MinValue;
protected int64 mWriteDirtyEnd = -Int32.MinValue;
public override int64 Position
{
get
{
return mPos;
}
set
{
mPos = Math.Min(value, Length);
}
}
public override int64 Length
{
get
{
UpdateLength();
return Math.Max(mUnderlyingLength, mWriteDirtyEnd);
}
}
protected abstract void UpdateLength();
protected abstract Result<int> TryReadUnderlying(int64 pos, Span<uint8> data);
protected abstract Result<int> TryWriteUnderlying(int64 pos, Span<uint8> data);
public ~this()
{
Flush();
}
public override Result<void> Seek(int64 pos, SeekKind seekKind = .Absolute)
{
int64 length = Length;
int64 newPos;
switch (seekKind)
{
case .Absolute:
mPos = Math.Min(pos, length);
if (pos > length)
return .Err;
case .FromEnd:
newPos = length - pos;
case .Relative:
mPos = Math.Min(mPos + pos, length);
}
return .Ok;
}
public void MakeBuffer(int size)
{
delete mBuffer;
mBuffer = new uint8[size];
}
public override Result<int> TryRead(Span<uint8> data)
{
int64 spaceLeft = mBufferEnd - mPos;
if (data.Length <= spaceLeft)
{
Internal.MemCpy(data.Ptr, mBuffer.Ptr + (mPos - mBufferPos), data.Length);
mPos += data.Length;
return data.Length;
}
int64 readStart = mPos;
var data;
if (spaceLeft > 0)
{
Internal.MemCpy(data.Ptr, mBuffer.Ptr + (mPos - mBufferPos), spaceLeft);
mPos += spaceLeft;
data.RemoveFromStart(spaceLeft);
}
if (mWriteDirtyPos >= 0)
Try!(Flush());
if ((mBuffer == null) || (data.Length > mBuffer.Count))
{
var result = TryReadUnderlying(mPos, data);
if (result case .Ok(let len))
mPos += len;
return mPos - readStart;
}
var result = TryReadUnderlying(mPos, mBuffer);
switch (result)
{
case .Ok(let len):
mBufferPos = mPos;
mBufferEnd = mPos + len;
int readLen = Math.Min(len, data.Length);
Internal.MemCpy(data.Ptr, mBuffer.Ptr, readLen);
mPos += readLen;
return mPos - readStart;
case .Err:
return result;
}
}
public override Result<int> TryWrite(Span<uint8> data)
{
var data;
if ((mWriteDirtyEnd >= 0) && (mWriteDirtyEnd != mPos))
{
Try!(Flush());
}
int writeCount = 0;
if (mWriteDirtyEnd >= 0)
{
int64 spaceLeft = (mBufferPos + mBuffer.Count) - mPos;
if (data.Length <= spaceLeft)
writeCount = data.Length;
else
writeCount = spaceLeft;
if (writeCount > 0)
{
Internal.MemCpy(mBuffer.Ptr + (mPos - mBufferPos), data.Ptr, writeCount);
mPos += writeCount;
mWriteDirtyEnd = Math.Max(mWriteDirtyEnd, mPos);
mBufferEnd = Math.Max(mBufferEnd, mPos);
if (writeCount == data.Length)
return writeCount;
data.RemoveFromStart(writeCount);
}
}
Try!(Flush());
if ((mBuffer == null) || (data.Length > mBuffer.Count))
{
var result = TryWriteUnderlying(mPos, data);
if (result case .Ok(let len))
mPos += len;
writeCount += result;
return writeCount;
}
mBufferPos = mPos;
mWriteDirtyPos = mPos;
Internal.MemCpy(mBuffer.Ptr, data.Ptr, data.Length);
mPos += data.Length;
mBufferEnd = mPos;
mWriteDirtyEnd = mPos;
writeCount += data.Length;
return writeCount;
}
public override Result<void> Flush()
{
if (mWriteDirtyPos >= 0)
{
Try!(TryWriteUnderlying(mWriteDirtyPos, .(mBuffer.Ptr + (mWriteDirtyPos - mBufferPos), (.)(mWriteDirtyEnd - mWriteDirtyPos))));
mWriteDirtyPos = -Int32.MinValue;
mWriteDirtyEnd = -Int32.MinValue;
}
return .Ok;
}
public override Result<void> Close()
{
return Flush();
}
}
}

View file

@ -101,9 +101,9 @@ namespace System.IO
return .Ok(count);
}
public override void Close()
public override Result<void> Close()
{
return .Ok;
}
public void RemoveFromStart(int count)

View file

@ -31,7 +31,7 @@ namespace System.IO
public ~this()
{
Close();
Delete();
}
public override Result<void> Seek(int64 pos, SeekKind seekKind = .Absolute)
@ -52,7 +52,7 @@ namespace System.IO
return numBytesRead;
}
public Result<int> TryRead(Span<uint8> data, int timeoutMS)
public virtual Result<int> TryRead(Span<uint8> data, int timeoutMS)
{
Platform.BfpFileResult result = .Ok;
int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, timeoutMS, &result);
@ -70,21 +70,28 @@ namespace System.IO
return numBytesWritten;
}
public override void Close()
public override Result<void> Close()
{
if (mBfpFile != null)
Platform.BfpFile_Release(mBfpFile);
mBfpFile = null;
return .Ok;
}
public override void Flush()
public override Result<void> Flush()
{
if (mBfpFile != null)
Platform.BfpFile_Flush(mBfpFile);
return .Ok;
}
protected virtual void Delete()
{
Close();
}
}
class FileStream : FileStreamBase
class UnbufferedFileStream : FileStreamBase
{
FileAccess mFileAccess;
@ -211,10 +218,228 @@ namespace System.IO
mFileAccess = access;
}
public override void Close()
public override Result<void> Close()
{
base.Close();
mFileAccess = default;
if (base.Close() case .Err)
return .Err;
return .Ok;
}
}
class BufferedFileStream : BufferedStream
{
protected Platform.BfpFile* mBfpFile;
protected int64 mBfpFilePos;
FileAccess mFileAccess;
public this()
{
}
public ~this()
{
Delete();
}
protected virtual void Delete()
{
Close();
}
public this(Platform.BfpFile* handle, FileAccess access, int32 bufferSize, bool isAsync)
{
mBfpFile = handle;
mFileAccess = access;
}
public override bool CanRead
{
get
{
return mFileAccess.HasFlag(FileAccess.Read);
}
}
public override bool CanWrite
{
get
{
return mFileAccess.HasFlag(FileAccess.Write);
}
}
public Result<void, FileOpenError> Create(StringView path, FileAccess access = .ReadWrite, FileShare share = .None, int bufferSize = 4096, FileOptions options = .None, SecurityAttributes* secAttrs = null)
{
return Open(path, FileMode.Create, access, share, bufferSize, options, secAttrs);
}
public Result<void, FileOpenError> Open(StringView path, FileAccess access = .ReadWrite, FileShare share = .None, int bufferSize = 4096, FileOptions options = .None, SecurityAttributes* secAttrs = null)
{
return Open(path, FileMode.Open, access, share, bufferSize, options, secAttrs);
}
public Result<void, FileOpenError> OpenStd(Platform.BfpFileStdKind stdKind)
{
Platform.BfpFileResult fileResult = .Ok;
mBfpFile = Platform.BfpFile_GetStd(stdKind, &fileResult);
mFileAccess = .ReadWrite;
if ((mBfpFile == null) || (fileResult != .Ok))
{
switch (fileResult)
{
case .ShareError:
return .Err(.SharingViolation);
case .NotFound:
return .Err(.NotFound);
default:
return .Err(.Unknown);
}
}
return .Ok;
}
public Result<void, FileOpenError> Open(StringView path, FileMode mode, FileAccess access, FileShare share = .None, int bufferSize = 4096, FileOptions options = .None, SecurityAttributes* secAttrs = null)
{
Runtime.Assert(mBfpFile == null);
Platform.BfpFileCreateKind createKind = .CreateAlways;
Platform.BfpFileCreateFlags createFlags = .None;
switch (mode)
{
case .CreateNew:
createKind = .CreateIfNotExists;
case .Create:
createKind = .CreateAlways;
case .Open:
createKind = .OpenExisting;
case .OpenOrCreate:
createKind = .CreateAlways;
case .Truncate:
createKind = .CreateAlways;
createFlags |= .Truncate;
case .Append:
createKind = .CreateAlways;
createFlags |= .Append;
}
if (access.HasFlag(.Read))
createFlags |= .Read;
if (access.HasFlag(.Write))
createFlags |= .Write;
if (share.HasFlag(.Read))
createFlags |= .ShareRead;
if (share.HasFlag(.Write))
createFlags |= .ShareWrite;
if (share.HasFlag(.Delete))
createFlags |= .ShareDelete;
Platform.BfpFileAttributes fileFlags = .Normal;
Platform.BfpFileResult fileResult = .Ok;
mBfpFile = Platform.BfpFile_Create(path.ToScopeCStr!(128), createKind, createFlags, fileFlags, &fileResult);
if ((mBfpFile == null) || (fileResult != .Ok))
{
switch (fileResult)
{
case .ShareError:
return .Err(.SharingViolation);
case .NotFound:
return .Err(.NotFound);
default:
return .Err(.Unknown);
}
}
mFileAccess = access;
MakeBuffer(bufferSize);
return .Ok;
}
public void Attach(Platform.BfpFile* bfpFile, FileAccess access = .ReadWrite)
{
Close();
mBfpFile = bfpFile;
mFileAccess = access;
}
public override Result<void> Close()
{
var hadError = Flush() case .Err;
if (mBfpFile != null)
Platform.BfpFile_Release(mBfpFile);
mBfpFile = null;
mFileAccess = default;
if (hadError)
return .Err;
return .Ok;
}
protected override void UpdateLength()
{
mUnderlyingLength = Platform.BfpFile_GetFileSize(mBfpFile);
}
protected override Result<int> TryReadUnderlying(int64 pos, Span<uint8> data)
{
if (mBfpFilePos != pos)
{
int64 newPos = Platform.BfpFile_Seek(mBfpFile, pos, .Absolute);
if (newPos != pos)
return .Err;
mBfpFilePos = pos;
}
Platform.BfpFileResult result = .Ok;
int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, -1, &result);
if ((result != .Ok) && (result != .PartialData))
return .Err;
mBfpFilePos += numBytesRead;
return numBytesRead;
}
protected override Result<int> TryWriteUnderlying(int64 pos, Span<uint8> data)
{
if (mBfpFilePos != pos)
{
int64 newPos = Platform.BfpFile_Seek(mBfpFile, pos, .Absolute);
if (newPos != pos)
return .Err;
mBfpFilePos = pos;
}
Platform.BfpFileResult result = .Ok;
int numBytesRead = Platform.BfpFile_Write(mBfpFile, data.Ptr, data.Length, -1, &result);
if ((result != .Ok) && (result != .PartialData))
return .Err;
mBfpFilePos += numBytesRead;
return numBytesRead;
}
public Result<int> TryRead(Span<uint8> data, int timeoutMS)
{
if (mBfpFilePos != mPos)
{
int64 newPos = Platform.BfpFile_Seek(mBfpFile, mPos, .Absolute);
if (newPos != mPos)
return .Err;
mBfpFilePos = mPos;
}
Platform.BfpFileResult result = .Ok;
int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, timeoutMS, &result);
if ((result != .Ok) && (result != .PartialData))
return .Err;
return numBytesRead;
}
}
class FileStream : BufferedFileStream
{
}
}

View file

@ -71,9 +71,9 @@ namespace System.IO
return .Ok(count);
}
public override void Close()
public override Result<void> Close()
{
return .Ok;
}
}
}

View file

@ -56,9 +56,9 @@ namespace System.IO
return .Ok(data.Length);
}
public override void Close()
public override Result<void> Close()
{
return .Ok;
}
}
}

View file

@ -61,7 +61,7 @@ namespace System.IO
public abstract Result<int> TryRead(Span<uint8> data);
public abstract Result<int> TryWrite(Span<uint8> data);
public abstract void Close();
public abstract Result<void> Close();
//Read value from stream without changing position. Position won't change even if it returns .Err
public Result<T> Peek<T>() where T : struct
@ -134,10 +134,16 @@ namespace System.IO
public Result<T> Read<T>() where T : struct
{
T val = ?;
int size = Try!(TryRead(.((uint8*)&val, sizeof(T))));
if (size != sizeof(T))
var result = TryRead(.((uint8*)&val, sizeof(T)));
switch (result)
{
case .Ok(let size):
if (size != sizeof(T))
return .Err;
return .Ok(val);
case .Err:
return .Err;
return .Ok(val);
}
}
public Result<void> Write<T>(T val) where T : struct
@ -186,8 +192,9 @@ namespace System.IO
return .Ok;
}
public virtual void Flush()
public virtual Result<void> Flush()
{
return .Ok;
}
public void Align(int alignSize)

View file

@ -157,9 +157,9 @@ namespace System.IO
return .Ok(count);
}
public override void Close()
public override Result<void> Close()
{
return .Ok;
}
}
}

View file

@ -90,14 +90,14 @@ namespace System.IO
}
}
public override void Close()
public override Result<void> Close()
{
mChildStream.Close();
return mChildStream.Close();
}
public override void Flush()
public override Result<void> Flush()
{
mChildStream.Flush();
return mChildStream.Flush();
}
}
}

View file

@ -54,9 +54,9 @@ namespace System
return .Ok(data.Length);
}
public override void Close()
public override Result<void> Close()
{
return .Ok;
}
}

View file

@ -1451,6 +1451,9 @@ namespace System
[CLink, CallingConvention(.Stdcall)]
public static extern Handle OpenFileMappingA(uint32 dwDesiredAccess, IntBool bInheritHandle, char8* lpName);
[CLink, CallingConvention(.Stdcall)]
public static extern Handle CreateFileMappingA(Handle hFile, SecurityAttributes* securityAttrs, uint32 flProtect, uint32 dwMaximumSizeHigh, uint32 dwMaximumSizeLow, char8* lpName);
[CLink, CallingConvention(.Stdcall)]
public static extern void* MapViewOfFile(Handle hFileMappingObject, uint32 dwDesiredAccess, uint32 dwFileOffsetHigh, uint32 dwFileOffsetLow, int dwNumberOfBytesToMap);