diff --git a/BeefLibs/corlib/src/Array.bf b/BeefLibs/corlib/src/Array.bf index d206d93c..bf197ba2 100644 --- a/BeefLibs/corlib/src/Array.bf +++ b/BeefLibs/corlib/src/Array.bf @@ -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; diff --git a/BeefLibs/corlib/src/IO/BufferedStream.bf b/BeefLibs/corlib/src/IO/BufferedStream.bf new file mode 100644 index 00000000..7b88c492 --- /dev/null +++ b/BeefLibs/corlib/src/IO/BufferedStream.bf @@ -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 TryReadUnderlying(int64 pos, Span data); + protected abstract Result TryWriteUnderlying(int64 pos, Span data); + + public ~this() + { + Flush(); + } + + public override Result 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 TryRead(Span 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 TryWrite(Span 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 Flush() + { + if (mWriteDirtyPos >= 0) + { + Try!(TryWriteUnderlying(mWriteDirtyPos, .(mBuffer.Ptr + (mWriteDirtyPos - mBufferPos), (.)(mWriteDirtyEnd - mWriteDirtyPos)))); + mWriteDirtyPos = -Int32.MinValue; + mWriteDirtyEnd = -Int32.MinValue; + } + + return .Ok; + } + + public override Result Close() + { + return Flush(); + } + } +} diff --git a/BeefLibs/corlib/src/IO/DynMemStream.bf b/BeefLibs/corlib/src/IO/DynMemStream.bf index 03be01d1..1fd2e235 100644 --- a/BeefLibs/corlib/src/IO/DynMemStream.bf +++ b/BeefLibs/corlib/src/IO/DynMemStream.bf @@ -101,9 +101,9 @@ namespace System.IO return .Ok(count); } - public override void Close() + public override Result Close() { - + return .Ok; } public void RemoveFromStart(int count) diff --git a/BeefLibs/corlib/src/IO/FileStream.bf b/BeefLibs/corlib/src/IO/FileStream.bf index fa51f395..6ffd0e44 100644 --- a/BeefLibs/corlib/src/IO/FileStream.bf +++ b/BeefLibs/corlib/src/IO/FileStream.bf @@ -31,7 +31,7 @@ namespace System.IO public ~this() { - Close(); + Delete(); } public override Result Seek(int64 pos, SeekKind seekKind = .Absolute) @@ -52,7 +52,7 @@ namespace System.IO return numBytesRead; } - public Result TryRead(Span data, int timeoutMS) + public virtual Result TryRead(Span 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 Close() { if (mBfpFile != null) Platform.BfpFile_Release(mBfpFile); mBfpFile = null; + return .Ok; } - public override void Flush() + public override Result 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 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 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 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 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 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 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 TryReadUnderlying(int64 pos, Span 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 TryWriteUnderlying(int64 pos, Span 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 TryRead(Span 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 + { + + } } diff --git a/BeefLibs/corlib/src/IO/MemoryStream.bf b/BeefLibs/corlib/src/IO/MemoryStream.bf index 97ce6021..0980bb1c 100644 --- a/BeefLibs/corlib/src/IO/MemoryStream.bf +++ b/BeefLibs/corlib/src/IO/MemoryStream.bf @@ -71,9 +71,9 @@ namespace System.IO return .Ok(count); } - public override void Close() + public override Result Close() { - + return .Ok; } } } diff --git a/BeefLibs/corlib/src/IO/NullStream.bf b/BeefLibs/corlib/src/IO/NullStream.bf index 6f72dd9c..fdee358c 100644 --- a/BeefLibs/corlib/src/IO/NullStream.bf +++ b/BeefLibs/corlib/src/IO/NullStream.bf @@ -56,9 +56,9 @@ namespace System.IO return .Ok(data.Length); } - public override void Close() + public override Result Close() { - + return .Ok; } } } diff --git a/BeefLibs/corlib/src/IO/Stream.bf b/BeefLibs/corlib/src/IO/Stream.bf index b0c73878..6798c4aa 100644 --- a/BeefLibs/corlib/src/IO/Stream.bf +++ b/BeefLibs/corlib/src/IO/Stream.bf @@ -61,7 +61,7 @@ namespace System.IO public abstract Result TryRead(Span data); public abstract Result TryWrite(Span data); - public abstract void Close(); + public abstract Result Close(); //Read value from stream without changing position. Position won't change even if it returns .Err public Result Peek() where T : struct @@ -134,10 +134,16 @@ namespace System.IO public Result Read() 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 Write(T val) where T : struct @@ -186,8 +192,9 @@ namespace System.IO return .Ok; } - public virtual void Flush() + public virtual Result Flush() { + return .Ok; } public void Align(int alignSize) diff --git a/BeefLibs/corlib/src/IO/StringStream.bf b/BeefLibs/corlib/src/IO/StringStream.bf index 9d9459db..86990fed 100644 --- a/BeefLibs/corlib/src/IO/StringStream.bf +++ b/BeefLibs/corlib/src/IO/StringStream.bf @@ -157,9 +157,9 @@ namespace System.IO return .Ok(count); } - public override void Close() + public override Result Close() { - + return .Ok; } } } diff --git a/BeefLibs/corlib/src/IO/Substream.bf b/BeefLibs/corlib/src/IO/Substream.bf index 639aa2f8..e3d309a5 100644 --- a/BeefLibs/corlib/src/IO/Substream.bf +++ b/BeefLibs/corlib/src/IO/Substream.bf @@ -90,14 +90,14 @@ namespace System.IO } } - public override void Close() + public override Result Close() { - mChildStream.Close(); + return mChildStream.Close(); } - public override void Flush() + public override Result Flush() { - mChildStream.Flush(); + return mChildStream.Flush(); } } } diff --git a/BeefLibs/corlib/src/Test.bf b/BeefLibs/corlib/src/Test.bf index 81ba4d76..07524549 100644 --- a/BeefLibs/corlib/src/Test.bf +++ b/BeefLibs/corlib/src/Test.bf @@ -54,9 +54,9 @@ namespace System return .Ok(data.Length); } - public override void Close() + public override Result Close() { - + return .Ok; } } diff --git a/BeefLibs/corlib/src/Windows.bf b/BeefLibs/corlib/src/Windows.bf index db497823..36f2e8c3 100644 --- a/BeefLibs/corlib/src/Windows.bf +++ b/BeefLibs/corlib/src/Windows.bf @@ -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);