aboutsummaryrefslogtreecommitdiff
path: root/Utils/src/IO
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-01-08 16:01:54 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2023-01-08 16:01:54 -0500
commitde94d788e9a47432a7630a8215896b8dd3628599 (patch)
tree666dec06eef861d101cb6948aff52a3d354c8d73 /Utils/src/IO
parentbe6dc557a3b819248b014992eb96c1cb21f8112b (diff)
Reorder + analyzer cleanup
Diffstat (limited to 'Utils/src/IO')
-rw-r--r--Utils/src/IO/ArrayPoolStreamBuffer.cs70
-rw-r--r--Utils/src/IO/BackingStream.cs181
-rw-r--r--Utils/src/IO/FileOperations.cs105
-rw-r--r--Utils/src/IO/IDataAccumulator.cs64
-rw-r--r--Utils/src/IO/ISlindingWindowBuffer.cs91
-rw-r--r--Utils/src/IO/IVnTextReader.cs72
-rw-r--r--Utils/src/IO/InMemoryTemplate.cs196
-rw-r--r--Utils/src/IO/IsolatedStorageDirectory.cs154
-rw-r--r--Utils/src/IO/SlidingWindowBufferExtensions.cs213
-rw-r--r--Utils/src/IO/TemporayIsolatedFile.cs57
-rw-r--r--Utils/src/IO/VnMemoryStream.cs469
-rw-r--r--Utils/src/IO/VnStreamReader.cs180
-rw-r--r--Utils/src/IO/VnStreamWriter.cs292
-rw-r--r--Utils/src/IO/VnTextReaderExtensions.cs223
-rw-r--r--Utils/src/IO/WriteOnlyBufferedStream.cs255
15 files changed, 0 insertions, 2622 deletions
diff --git a/Utils/src/IO/ArrayPoolStreamBuffer.cs b/Utils/src/IO/ArrayPoolStreamBuffer.cs
deleted file mode 100644
index df366e3..0000000
--- a/Utils/src/IO/ArrayPoolStreamBuffer.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: ArrayPoolStreamBuffer.cs
-*
-* ArrayPoolStreamBuffer.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.Buffers;
-
-namespace VNLib.Utils.IO
-{
- internal class ArrayPoolStreamBuffer<T> : ISlindingWindowBuffer<T>
- {
- private readonly ArrayPool<T> _pool;
- private T[] _buffer;
-
- public ArrayPoolStreamBuffer(ArrayPool<T> pool, int bufferSize)
- {
- _pool = pool;
- _buffer = _pool.Rent(bufferSize);
- }
-
- public int WindowStartPos { get; set; }
- public int WindowEndPos { get; set; }
-
- public Memory<T> Buffer => _buffer.AsMemory();
-
- public void Advance(int count)
- {
- WindowEndPos += count;
- }
-
- public void AdvanceStart(int count)
- {
- WindowStartPos += count;
- }
-
- public void Close()
- {
- //Return buffer to pool
- _pool.Return(_buffer);
- _buffer = null;
- }
-
- public void Reset()
- {
- //Reset window positions
- WindowStartPos = 0;
- WindowEndPos = 0;
- }
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/BackingStream.cs b/Utils/src/IO/BackingStream.cs
deleted file mode 100644
index cb56b09..0000000
--- a/Utils/src/IO/BackingStream.cs
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: BackingStream.cs
-*
-* BackingStream.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// Provides basic stream support sync/async stream operations to a
- /// backing stream with virtual event methods. Provides a pass-through
- /// as best as possbile.
- /// </summary>
- public abstract class BackingStream<T> : Stream where T: Stream
- {
- /// <summary>
- /// The backing/underlying stream operations are being performed on
- /// </summary>
- protected T BaseStream { get; set; }
- /// <summary>
- /// A value that will cause all calls to write to throw <see cref="NotSupportedException"/>
- /// </summary>
- protected bool ForceReadOnly { get; set; }
- ///<inheritdoc/>
- public override bool CanRead => BaseStream.CanRead;
- ///<inheritdoc/>
- public override bool CanSeek => BaseStream.CanSeek;
- ///<inheritdoc/>
- public override bool CanWrite => BaseStream.CanWrite && !ForceReadOnly;
- ///<inheritdoc/>
- public override long Length => BaseStream.Length;
- ///<inheritdoc/>
- public override int WriteTimeout { get => BaseStream.WriteTimeout; set => BaseStream.WriteTimeout = value; }
- ///<inheritdoc/>
- public override int ReadTimeout { get => BaseStream.ReadTimeout; set => BaseStream.ReadTimeout = value; }
- ///<inheritdoc/>
- public override long Position { get => BaseStream.Position; set => BaseStream.Position = value; }
- ///<inheritdoc/>
- public override void Flush()
- {
- BaseStream.Flush();
- OnFlush();
- }
- ///<inheritdoc/>
- public override int Read(byte[] buffer, int offset, int count) => BaseStream.Read(buffer, offset, count);
- ///<inheritdoc/>
- public override int Read(Span<byte> buffer) => BaseStream.Read(buffer);
- ///<inheritdoc/>
- public override long Seek(long offset, SeekOrigin origin) => BaseStream.Seek(offset, origin);
- ///<inheritdoc/>
- public override void SetLength(long value) => BaseStream.SetLength(value);
- ///<inheritdoc/>
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (ForceReadOnly)
- {
- throw new NotSupportedException("Stream is set to readonly mode");
- }
- BaseStream.Write(buffer, offset, count);
- //Call onwrite function
- OnWrite(count);
- }
- ///<inheritdoc/>
- public override void Write(ReadOnlySpan<byte> buffer)
- {
- if (ForceReadOnly)
- {
- throw new NotSupportedException("Stream is set to readonly mode");
- }
- BaseStream.Write(buffer);
- //Call onwrite function
- OnWrite(buffer.Length);
- }
- ///<inheritdoc/>
- public override void Close()
- {
- BaseStream.Close();
- //Call on close function
- OnClose();
- }
-
- /// <summary>
- /// Raised directly after the base stream is closed, when a call to close is made
- /// </summary>
- protected virtual void OnClose() { }
- /// <summary>
- /// Raised directly after the base stream is flushed, when a call to flush is made
- /// </summary>
- protected virtual void OnFlush() { }
- /// <summary>
- /// Raised directly after a successfull write operation.
- /// </summary>
- /// <param name="count">The number of bytes written to the stream</param>
- protected virtual void OnWrite(int count) { }
-
- ///<inheritdoc/>
- public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- return BaseStream.ReadAsync(buffer, offset, count, cancellationToken);
- }
- ///<inheritdoc/>
- public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
- {
- return BaseStream.ReadAsync(buffer, cancellationToken);
- }
- ///<inheritdoc/>
- public override void CopyTo(Stream destination, int bufferSize) => BaseStream.CopyTo(destination, bufferSize);
- ///<inheritdoc/>
- public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
- {
- return BaseStream.CopyToAsync(destination, bufferSize, cancellationToken);
- }
- ///<inheritdoc/>
- public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- if (ForceReadOnly)
- {
- throw new NotSupportedException("Stream is set to readonly mode");
- }
- //We want to maintain pass through as much as possible, so supress warning
-#pragma warning disable CA1835 // Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync'
- await BaseStream.WriteAsync(buffer, offset, count, cancellationToken);
-#pragma warning restore CA1835 // Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync'
-
- //Call on-write and pass the number of bytes written
- OnWrite(count);
- }
- ///<inheritdoc/>
- public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
- {
- if (ForceReadOnly)
- {
- throw new NotSupportedException("Stream is set to readonly mode");
- }
- await BaseStream.WriteAsync(buffer, cancellationToken);
- //Call on-write and pass the length
- OnWrite(buffer.Length);
- }
- ///<inheritdoc/>
- public override async Task FlushAsync(CancellationToken cancellationToken)
- {
- await BaseStream.FlushAsync(cancellationToken);
- //Call onflush
- OnFlush();
- }
-
- ///<inheritdoc/>
- public override async ValueTask DisposeAsync()
- {
- //Dispose the base stream and await it
- await BaseStream.DisposeAsync();
- //Call onclose
- OnClose();
- //Suppress finalize
- GC.SuppressFinalize(this);
- }
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/FileOperations.cs b/Utils/src/IO/FileOperations.cs
deleted file mode 100644
index e040da4..0000000
--- a/Utils/src/IO/FileOperations.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: FileOperations.cs
-*
-* FileOperations.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.Runtime.InteropServices;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// Contains cross-platform optimized filesystem operations.
- /// </summary>
- public static class FileOperations
- {
- public const int INVALID_FILE_ATTRIBUTES = -1;
-
- [DllImport("Shlwapi", SetLastError = true, CharSet = CharSet.Auto)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- [return:MarshalAs(UnmanagedType.Bool)]
- private static unsafe extern bool PathFileExists(char* path);
- [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- [return:MarshalAs(UnmanagedType.I4)]
- private static unsafe extern int GetFileAttributes(char* path);
-
- static readonly bool IsWindows = OperatingSystem.IsWindows();
- /// <summary>
- /// Determines if a file exists. If application is current running in the Windows operating system, Shlwapi.PathFileExists is invoked,
- /// otherwise <see cref="File.Exists(string?)"/> is invoked
- /// </summary>
- /// <param name="filePath">the path to the file</param>
- /// <returns>True if the file can be opened, false otherwise</returns>
- public static bool FileExists(string filePath)
- {
- //If windows is detected, use the unmanged function
- if (!IsWindows)
- {
- return File.Exists(filePath);
- }
- unsafe
- {
- //Get a char pointer to the file path
- fixed (char* path = filePath)
- {
- //Invoke the winap file function
- return PathFileExists(path);
- }
- }
- }
-
- /// <summary>
- /// If Windows is detected at load time, gets the attributes for the specified file.
- /// </summary>
- /// <param name="filePath">The path to the existing file</param>
- /// <returns>The attributes of the file </returns>
- /// <exception cref="PathTooLongException"></exception>
- /// <exception cref="FileNotFoundException"></exception>
- /// <exception cref="UnauthorizedAccessException"></exception>
- public static FileAttributes GetAttributes(string filePath)
- {
- //If windows is detected, use the unmanged function
- if (!IsWindows)
- {
- return File.GetAttributes(filePath);
- }
- unsafe
- {
- //Get a char pointer to the file path
- fixed (char* path = filePath)
- {
- //Invoke the winap file function and cast the returned int value to file attributes
- int attr = GetFileAttributes(path);
- //Check for error
- if (attr == INVALID_FILE_ATTRIBUTES)
- {
- throw new FileNotFoundException("The requested file was not found", filePath);
- }
- //Cast to file attributes and return
- return (FileAttributes)attr;
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/IDataAccumulator.cs b/Utils/src/IO/IDataAccumulator.cs
deleted file mode 100644
index 5129a55..0000000
--- a/Utils/src/IO/IDataAccumulator.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: IDataAccumulator.cs
-*
-* IDataAccumulator.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// A data structure that represents a sliding window over a buffer
- /// for resetable forward-only reading or writing
- /// </summary>
- /// <typeparam name="T">The accumuation data type</typeparam>
- public interface IDataAccumulator<T>
- {
- /// <summary>
- /// Gets the number of available items within the buffer
- /// </summary>
- int AccumulatedSize { get; }
- /// <summary>
- /// The number of elements remaining in the buffer
- /// </summary>
- int RemainingSize { get; }
- /// <summary>
- /// The remaining space in the internal buffer as a contiguous segment
- /// </summary>
- Span<T> Remaining { get; }
- /// <summary>
- /// The buffer window over the accumulated data
- /// </summary>
- Span<T> Accumulated { get; }
-
- /// <summary>
- /// Advances the accumulator buffer window by the specified amount
- /// </summary>
- /// <param name="count">The number of elements accumulated</param>
- void Advance(int count);
-
- /// <summary>
- /// Resets the internal state of the accumulator
- /// </summary>
- void Reset();
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/ISlindingWindowBuffer.cs b/Utils/src/IO/ISlindingWindowBuffer.cs
deleted file mode 100644
index ff4e142..0000000
--- a/Utils/src/IO/ISlindingWindowBuffer.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: ISlindingWindowBuffer.cs
-*
-* ISlindingWindowBuffer.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// Represents a sliding window buffer for reading/wiriting data
- /// </summary>
- /// <typeparam name="T"></typeparam>
- public interface ISlindingWindowBuffer<T> : IDataAccumulator<T>
- {
- /// <summary>
- /// The number of elements remaining in the buffer
- /// </summary>
- int IDataAccumulator<T>.RemainingSize => Buffer.Length - WindowEndPos;
- /// <summary>
- /// The remaining space in the internal buffer as a contiguous segment
- /// </summary>
- Span<T> IDataAccumulator<T>.Remaining => RemainingBuffer.Span;
- /// <summary>
- /// The buffer window over the accumulated data
- /// </summary>
- Span<T> IDataAccumulator<T>.Accumulated => AccumulatedBuffer.Span;
- /// <summary>
- /// Gets the number of available items within the buffer
- /// </summary>
- int IDataAccumulator<T>.AccumulatedSize => WindowEndPos - WindowStartPos;
-
- /// <summary>
- /// The starting positon of the available data within the buffer
- /// </summary>
- int WindowStartPos { get; }
- /// <summary>
- /// The ending position of the available data within the buffer
- /// </summary>
- int WindowEndPos { get; }
- /// <summary>
- /// Buffer memory wrapper
- /// </summary>
- Memory<T> Buffer { get; }
-
- /// <summary>
- /// Releases resources used by the current instance
- /// </summary>
- void Close();
- /// <summary>
- /// <para>
- /// Advances the begining of the accumulated data window.
- /// </para>
- /// <para>
- /// This method is used during reading to singal that data
- /// has been read from the internal buffer and the
- /// accumulator window can be shifted.
- /// </para>
- /// </summary>
- /// <param name="count">The number of elements to shift by</param>
- void AdvanceStart(int count);
-
- /// <summary>
- /// Gets a window within the buffer of available buffered data
- /// </summary>
- Memory<T> AccumulatedBuffer => Buffer[WindowStartPos..WindowEndPos];
- /// <summary>
- /// Gets the available buffer window to write data to
- /// </summary>
- Memory<T> RemainingBuffer => Buffer[WindowEndPos..];
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/IVnTextReader.cs b/Utils/src/IO/IVnTextReader.cs
deleted file mode 100644
index 625ba78..0000000
--- a/Utils/src/IO/IVnTextReader.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: IVnTextReader.cs
-*
-* IVnTextReader.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.Text;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// Represents a streaming text reader with internal buffers
- /// </summary>
- public interface IVnTextReader
- {
- /// <summary>
- /// The base stream to read data from
- /// </summary>
- Stream BaseStream { get; }
- /// <summary>
- /// The character encoding used by the TextReader
- /// </summary>
- Encoding Encoding { get; }
- /// <summary>
- /// Number of available bytes of buffered data within the current buffer window
- /// </summary>
- int Available { get; }
- /// <summary>
- /// Gets or sets the line termination used to deliminate a line of data
- /// </summary>
- ReadOnlyMemory<byte> LineTermination { get; }
- /// <summary>
- /// The unread/available data within the internal buffer
- /// </summary>
- Span<byte> BufferedDataWindow { get; }
- /// <summary>
- /// Shifts the sliding buffer window by the specified number of bytes.
- /// </summary>
- /// <param name="count">The number of bytes read from the buffer</param>
- void Advance(int count);
- /// <summary>
- /// Reads data from the stream into the remaining buffer space for processing
- /// </summary>
- void FillBuffer();
- /// <summary>
- /// Compacts the available buffer space back to the begining of the buffer region
- /// and determines if there is room for more data to be buffered
- /// </summary>
- /// <returns>The remaining buffer space if any</returns>
- ERRNO CompactBufferWindow();
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/InMemoryTemplate.cs b/Utils/src/IO/InMemoryTemplate.cs
deleted file mode 100644
index 12f9092..0000000
--- a/Utils/src/IO/InMemoryTemplate.cs
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: InMemoryTemplate.cs
-*
-* InMemoryTemplate.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-using VNLib.Utils.Extensions;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// Represents a lazily loaded file stored in memory, with a change mointor
- /// that reloads the template if the file was modified in the filesystem
- /// </summary>
- public abstract class InMemoryTemplate : VnDisposeable
- {
- protected ManualResetEventSlim TemplateLock;
- private readonly FileSystemWatcher? Watcher;
- private bool Modified;
- private VnMemoryStream templateBuffer;
- protected readonly FileInfo TemplateFile;
-
- /// <summary>
- /// Gets the name of the template
- /// </summary>
- public abstract string TemplateName { get; }
-
- /// <summary>
- /// Creates a new in-memory copy of a file that will detect changes and refresh
- /// </summary>
- /// <param name="listenForChanges">Should changes to the template file be moniored for changes, and reloaded as necessary</param>
- /// <param name="path">The path of the file template</param>
- protected InMemoryTemplate(string path, bool listenForChanges = true)
- {
- TemplateFile = new FileInfo(path);
- TemplateLock = new(true);
- //Make sure the file exists
- if (!TemplateFile.Exists)
- {
- throw new FileNotFoundException("Template file does not exist");
- }
- if (listenForChanges)
- {
- //Setup a watcher to reload the template when modified
- Watcher = new FileSystemWatcher(TemplateFile.DirectoryName)
- {
- EnableRaisingEvents = true,
- IncludeSubdirectories = false,
- NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size
- };
- Watcher.Changed += Watcher_Changed;
- }
- //Set modified flag to make sure the template is read on first use
- this.Modified = true;
- }
-
- private void Watcher_Changed(object sender, FileSystemEventArgs e)
- {
- //Make sure the event was raied for this template
- if (!e.FullPath.Equals(TemplateFile.FullName, StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- TemplateLock.Reset();
- try
- {
- //Set modified flag
- Modified = true;
- //Refresh the fileinfo object
- TemplateFile.Refresh();
- //Invoke onmodifed function
- OnModifed();
- }
- finally
- {
- TemplateLock.Set();
- }
- }
-
- /// <summary>
- /// Gets a cached copy of the template data
- /// </summary>
- protected VnMemoryStream GetTemplateData()
- {
- //Make sure access is synchronized incase the file gets updated during access on another thread
- TemplateLock.Wait();
- //Determine if the file has been modified and needs to be reloaded
- if (Modified)
- {
- TemplateLock.Reset();
- try
- {
- //Read a new copy of the templte into mem
- ReadFile();
- }
- finally
- {
- TemplateLock.Set();
- }
- }
- //Return a copy of the memory stream
- return templateBuffer.GetReadonlyShallowCopy();
- }
- /// <summary>
- /// Updates the internal copy of the file to its memory representation
- /// </summary>
- protected void ReadFile()
- {
- //Open the file stream
- using FileStream fs = TemplateFile.OpenRead();
- //Dispose the old template buffer
- templateBuffer?.Dispose();
- //Create a new stream for storing the cached copy
- VnMemoryStream newBuf = new();
- try
- {
- fs.CopyTo(newBuf, null);
- }
- catch
- {
- newBuf.Dispose();
- throw;
- }
- //Create the readonly copy
- templateBuffer = VnMemoryStream.CreateReadonly(newBuf);
- //Clear the modified flag
- Modified = false;
- }
- /// <summary>
- /// Updates the internal copy of the file to its memory representation, asynchronously
- /// </summary>
- /// <param name="cancellationToken"></param>
- /// <returns>A task that completes when the file has been copied into memory</returns>
- protected async Task ReadFileAsync(CancellationToken cancellationToken = default)
- {
- //Open the file stream
- await using FileStream fs = TemplateFile.OpenRead();
- //Dispose the old template buffer
- templateBuffer?.Dispose();
- //Create a new stream for storing the cached copy
- VnMemoryStream newBuf = new();
- try
- {
- //Copy async
- await fs.CopyToAsync(newBuf, 8192, Memory.Memory.Shared, cancellationToken);
- }
- catch
- {
- newBuf.Dispose();
- throw;
- }
- //Create the readonly copy
- templateBuffer = VnMemoryStream.CreateReadonly(newBuf);
- //Clear the modified flag
- Modified = false;
- }
-
- /// <summary>
- /// Invoked when the template file has been modifed. Note: This event is raised
- /// while the <see cref="TemplateLock"/> is held.
- /// </summary>
- protected abstract void OnModifed();
-
- ///<inheritdoc/>
- protected override void Free()
- {
- //Dispose the watcher
- Watcher?.Dispose();
- //free the stream
- templateBuffer?.Dispose();
- }
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/IsolatedStorageDirectory.cs b/Utils/src/IO/IsolatedStorageDirectory.cs
deleted file mode 100644
index 65460ff..0000000
--- a/Utils/src/IO/IsolatedStorageDirectory.cs
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: IsolatedStorageDirectory.cs
-*
-* IsolatedStorageDirectory.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.IO.IsolatedStorage;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// Represents an open directory within an <see cref="IsolatedStorageFile"/> store for which files can be created, opened, or deleted.
- /// </summary>
- public sealed class IsolatedStorageDirectory : IsolatedStorage
- {
- private readonly string DirectoryPath;
- private readonly IsolatedStorageFile Storage;
- /// <summary>
- /// Creates a new <see cref="IsolatedStorageDirectory"/> within the specified file using the directory name.
- /// </summary>
- /// <param name="storage">A configured and open <see cref="IsolatedStorageFile"/></param>
- /// <param name="dir">The directory name to open or create within the store</param>
- public IsolatedStorageDirectory(IsolatedStorageFile storage, string dir)
- {
- this.Storage = storage;
- this.DirectoryPath = dir;
- //If the directory doesnt exist, create it
- if (!this.Storage.DirectoryExists(dir))
- this.Storage.CreateDirectory(dir);
- }
-
- private IsolatedStorageDirectory(IsolatedStorageDirectory parent, string dirName)
- {
- //Store ref to parent dir
- Parent = parent;
- //Referrence store
- this.Storage = parent.Storage;
- //Add the name of this dir to the end of the specified dir path
- this.DirectoryPath = Path.Combine(parent.DirectoryPath, dirName);
- }
-
- /// <summary>
- /// Creates a file by its path name within the currnet directory
- /// </summary>
- /// <param name="fileName">The name of the file</param>
- /// <returns>The open file</returns>
- /// <exception cref="IsolatedStorageException"></exception>
- /// <exception cref="ObjectDisposedException"></exception>
- /// <exception cref="DirectoryNotFoundException"></exception>
- public IsolatedStorageFileStream CreateFile(string fileName)
- {
- return this.Storage.CreateFile(Path.Combine(DirectoryPath, fileName));
- }
- /// <summary>
- /// Removes a file from the current directory
- /// </summary>
- /// <param name="fileName">The path of the file to remove</param>
- /// <exception cref="IsolatedStorageException"></exception>
- public void DeleteFile(string fileName)
- {
- this.Storage.DeleteFile(Path.Combine(this.DirectoryPath, fileName));
- }
- /// <summary>
- /// Opens a file that exists within the current directory
- /// </summary>
- /// <param name="fileName">Name with extension of the file</param>
- /// <param name="mode">File mode</param>
- /// <param name="access">File access</param>
- /// <returns>The open <see cref="IsolatedStorageFileStream"/> from the current directory</returns>
- public IsolatedStorageFileStream OpenFile(string fileName, FileMode mode, FileAccess access)
- {
- return this.Storage.OpenFile(Path.Combine(DirectoryPath, fileName), mode, access);
- }
- /// <summary>
- /// Opens a file that exists within the current directory
- /// </summary>
- /// <param name="fileName">Name with extension of the file</param>
- /// <param name="mode">File mode</param>
- /// <param name="access">File access</param>
- /// <param name="share">The file shareing mode</param>
- /// <returns>The open <see cref="IsolatedStorageFileStream"/> from the current directory</returns>
- public IsolatedStorageFileStream OpenFile(string fileName, FileMode mode, FileAccess access, FileShare share)
- {
- return this.Storage.OpenFile(Path.Combine(DirectoryPath, fileName), mode, access, share);
- }
-
- /// <summary>
- /// Determiens if the specified file path refers to an existing file within the directory
- /// </summary>
- /// <param name="fileName">The name of the file to search for</param>
- /// <returns>True if the file exists within the current directory</returns>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="ObjectDisposedException"></exception>
- /// <exception cref="IsolatedStorageException"></exception>
- /// <exception cref="InvalidOperationException"></exception>
- public bool FileExists(string fileName)
- {
- return this.Storage.FileExists(Path.Combine(this.DirectoryPath, fileName));
- }
-
- /// <summary>
- /// Removes the directory and its contents from the store
- /// </summary>
- public override void Remove()
- {
- Storage.DeleteDirectory(this.DirectoryPath);
- }
-
- public override long AvailableFreeSpace => Storage.AvailableFreeSpace;
- public override long Quota => Storage.Quota;
- public override long UsedSize => Storage.UsedSize;
- public override bool IncreaseQuotaTo(long newQuotaSize) => Storage.IncreaseQuotaTo(newQuotaSize);
-
- /// <summary>
- /// The parent <see cref="IsolatedStorageDirectory"/> this directory is a child within. null if there are no parent directories
- /// above this dir
- /// </summary>
-
- public IsolatedStorageDirectory? Parent { get; }
-#nullable disable
-
- /// <summary>
- /// Creates a child directory within the current directory
- /// </summary>
- /// <param name="directoryName">The name of the child directory</param>
- /// <returns>A new <see cref="IsolatedStorageDirectory"/> for which <see cref="IsolatedStorageFileStream"/>s can be opened/created</returns>
- /// <exception cref="ArgumentException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- public IsolatedStorageDirectory CreateChildDirectory(string directoryName)
- {
- return new IsolatedStorageDirectory(this, directoryName);
- }
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/SlidingWindowBufferExtensions.cs b/Utils/src/IO/SlidingWindowBufferExtensions.cs
deleted file mode 100644
index 0509061..0000000
--- a/Utils/src/IO/SlidingWindowBufferExtensions.cs
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: SlidingWindowBufferExtensions.cs
-*
-* SlidingWindowBufferExtensions.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-using VNLib.Utils.Memory;
-using VNLib.Utils.Extensions;
-using System.Runtime.CompilerServices;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// Extention methods for <see cref="ISlindingWindowBuffer{T}"/>
- /// </summary>
- public static class SlidingWindowBufferExtensions
- {
- /// <summary>
- /// Shifts/resets the current buffered data window down to the
- /// begining of the buffer if the buffer window is shifted away
- /// from the begining.
- /// </summary>
- /// <returns>The number of bytes of available space in the buffer</returns>
- public static ERRNO CompactBufferWindow<T>(this ISlindingWindowBuffer<T> sBuf)
- {
- //Nothing to compact if the starting data pointer is at the beining of the window
- if (sBuf.WindowStartPos > 0)
- {
- //Get span over engire buffer
- Span<T> buffer = sBuf.Buffer.Span;
- //Get data within window
- Span<T> usedData = sBuf.Accumulated;
- //Copy remaining to the begining of the buffer
- usedData.CopyTo(buffer);
-
- //Reset positions, then advance to the specified size
- sBuf.Reset();
- sBuf.Advance(usedData.Length);
- }
- //Return the number of bytes of available space
- return sBuf.RemainingSize;
- }
-
- /// <summary>
- /// Appends the specified data to the end of the buffer
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="sBuf"></param>
- /// <param name="val">The value to append to the end of the buffer</param>
- /// <exception cref="IndexOutOfRangeException"></exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void Append<T>(this IDataAccumulator<T> sBuf, T val)
- {
- //Set the value at first position
- sBuf.Remaining[0] = val;
- //Advance by 1
- sBuf.Advance(1);
- }
- /// <summary>
- /// Appends the specified data to the end of the buffer
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="sBuf"></param>
- /// <param name="val">The value to append to the end of the buffer</param>
- /// <exception cref="ArgumentException"></exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void Append<T>(this IDataAccumulator<T> sBuf, ReadOnlySpan<T> val)
- {
- val.CopyTo(sBuf.Remaining);
- sBuf.Advance(val.Length);
- }
- /// <summary>
- /// Formats and appends a value type to the accumulator with proper endianess
- /// </summary>
- /// <typeparam name="T">The value type to appent</typeparam>
- /// <param name="accumulator">The binary accumulator to append</param>
- /// <param name="value">The value type to append</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void Append<T>(this IDataAccumulator<byte> accumulator, T value) where T: unmanaged
- {
- //Use forward reader for the memory extension to append a value type to a binary accumulator
- ForwardOnlyWriter<byte> w = new(accumulator.Remaining);
- w.Append(value);
- accumulator.Advance(w.Written);
- }
-
- /// <summary>
- /// Attempts to write as much data as possible to the remaining space
- /// in the buffer and returns the number of bytes accumulated.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="accumulator"></param>
- /// <param name="value">The value to accumulate</param>
- /// <returns>The number of bytes accumulated</returns>
- public static ERRNO TryAccumulate<T>(this IDataAccumulator<T> accumulator, ReadOnlySpan<T> value)
- {
- //Calc data size and reserve space for final crlf
- int dataToCopy = Math.Min(value.Length, accumulator.RemainingSize);
-
- //Write as much data as possible
- accumulator.Append(value[..dataToCopy]);
-
- //Return number of bytes not written
- return dataToCopy;
- }
-
- /// <summary>
- /// Appends a <see cref="ISpanFormattable"/> instance to the end of the accumulator
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="accumulator"></param>
- /// <param name="formattable">The formattable instance to write to the accumulator</param>
- /// <param name="format">The format arguments</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void Append<T>(this IDataAccumulator<char> accumulator, in T formattable, ReadOnlySpan<char> format = default) where T : struct, ISpanFormattable
- {
- ForwardOnlyWriter<char> writer = new(accumulator.Remaining);
- writer.Append(formattable, format);
- accumulator.Advance(writer.Written);
- }
-
- /// <summary>
- /// Uses the remaining data buffer to compile a <see cref="IStringSerializeable"/>
- /// instance, then advances the accumulator by the number of characters used.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="accumulator"></param>
- /// <param name="compileable">The <see cref="IStringSerializeable"/> instance to compile</param>
- public static void Append<T>(this IDataAccumulator<char> accumulator, in T compileable) where T : IStringSerializeable
- {
- //Write directly to the remaining space
- int written = compileable.Compile(accumulator.Remaining);
- //Advance the writer
- accumulator.Advance(written);
- }
-
- /// <summary>
- /// Reads available data from the current window and writes as much as possible it to the supplied buffer
- /// and advances the buffer window
- /// </summary>
- /// <typeparam name="T">Element type</typeparam>
- /// <param name="sBuf"></param>
- /// <param name="buffer">The output buffer to write data to</param>
- /// <returns>The number of elements written to the buffer</returns>
- public static ERRNO Read<T>(this ISlindingWindowBuffer<T> sBuf, in Span<T> buffer)
- {
- //Calculate the amount of data to copy
- int dataToCopy = Math.Min(buffer.Length, sBuf.AccumulatedSize);
- //Copy the data to the buffer
- sBuf.Accumulated[..dataToCopy].CopyTo(buffer);
- //Advance the window
- sBuf.AdvanceStart(dataToCopy);
- //Return the number of bytes copied
- return dataToCopy;
- }
-
- /// <summary>
- /// Fills the remaining window space of the current accumulator with
- /// data from the specified stream asynchronously.
- /// </summary>
- /// <param name="accumulator"></param>
- /// <param name="input">The stream to read data from</param>
- /// <param name="cancellationToken">A token to cancel the operation</param>
- /// <returns>A value task representing the operation</returns>
- public static async ValueTask AccumulateDataAsync(this ISlindingWindowBuffer<byte> accumulator, Stream input, CancellationToken cancellationToken)
- {
- //Get a buffer from the end of the current window to the end of the buffer
- Memory<byte> bufWindow = accumulator.RemainingBuffer;
- //Read from stream async
- int read = await input.ReadAsync(bufWindow, cancellationToken);
- //Update the end of the buffer window to the end of the read data
- accumulator.Advance(read);
- }
- /// <summary>
- /// Fills the remaining window space of the current accumulator with
- /// data from the specified stream.
- /// </summary>
- /// <param name="accumulator"></param>
- /// <param name="input">The stream to read data from</param>
- public static void AccumulateData(this IDataAccumulator<byte> accumulator, Stream input)
- {
- //Get a buffer from the end of the current window to the end of the buffer
- Span<byte> bufWindow = accumulator.Remaining;
- //Read from stream async
- int read = input.Read(bufWindow);
- //Update the end of the buffer window to the end of the read data
- accumulator.Advance(read);
- }
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/TemporayIsolatedFile.cs b/Utils/src/IO/TemporayIsolatedFile.cs
deleted file mode 100644
index 3bee92b..0000000
--- a/Utils/src/IO/TemporayIsolatedFile.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: TemporayIsolatedFile.cs
-*
-* TemporayIsolatedFile.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.IO.IsolatedStorage;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// Allows for temporary files to be generated, used, then removed from an <see cref="IsolatedStorageFile"/>
- /// </summary>
- public sealed class TemporayIsolatedFile : BackingStream<IsolatedStorageFileStream>
- {
- private readonly IsolatedStorageDirectory Storage;
- private readonly string Filename;
- /// <summary>
- /// Creates a new temporary filestream within the specified <see cref="IsolatedStorageFile"/>
- /// </summary>
- /// <param name="storage">The file store to genreate temporary files within</param>
- public TemporayIsolatedFile(IsolatedStorageDirectory storage)
- {
- //Store ref
- this.Storage = storage;
- //Creaet a new random filename
- this.Filename = Path.GetRandomFileName();
- //try to created a new file within the isolaged storage
- this.BaseStream = storage.CreateFile(this.Filename);
- }
- protected override void OnClose()
- {
- //Remove the file from the storage
- Storage.DeleteFile(this.Filename);
- }
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/VnMemoryStream.cs b/Utils/src/IO/VnMemoryStream.cs
deleted file mode 100644
index 389a7da..0000000
--- a/Utils/src/IO/VnMemoryStream.cs
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: VnMemoryStream.cs
-*
-* VnMemoryStream.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Runtime.InteropServices;
-
-using VNLib.Utils.Extensions;
-
-namespace VNLib.Utils.IO
-{
-
- using Utils.Memory;
-
- /// <summary>
- /// Provides an unmanaged memory stream. Desigend to help reduce garbage collector load for
- /// high frequency memory operations. Similar to <see cref="UnmanagedMemoryStream"/>
- /// </summary>
- public sealed class VnMemoryStream : Stream, ICloneable
- {
- private long _position;
- private long _length;
- //Memory
- private readonly MemoryHandle<byte> _buffer;
- private bool IsReadonly;
- //Default owns handle
- private readonly bool OwnsHandle = true;
-
- /// <summary>
- /// Creates a new <see cref="VnMemoryStream"/> pointing to the begining of memory, and consumes the handle.
- /// </summary>
- /// <param name="handle"><see cref="MemoryHandle{T}"/> to consume</param>
- /// <param name="length">Length of the stream</param>
- /// <param name="readOnly">Should the stream be readonly?</param>
- /// <exception cref="ArgumentException"></exception>
- /// <returns>A <see cref="VnMemoryStream"/> wrapper to access the handle data</returns>
- public static VnMemoryStream ConsumeHandle(MemoryHandle<byte> handle, Int64 length, bool readOnly)
- {
- handle.ThrowIfClosed();
- return new VnMemoryStream(handle, length, readOnly, true);
- }
-
- /// <summary>
- /// Converts a writable <see cref="VnMemoryStream"/> to readonly to allow shallow copies
- /// </summary>
- /// <param name="stream">The stream to make readonly</param>
- /// <returns>The readonly stream</returns>
- public static VnMemoryStream CreateReadonly(VnMemoryStream stream)
- {
- //Set the readonly flag
- stream.IsReadonly = true;
- //Return the stream
- return stream;
- }
-
- /// <summary>
- /// Creates a new memory stream
- /// </summary>
- public VnMemoryStream() : this(Memory.Shared) { }
- /// <summary>
- /// Create a new memory stream where buffers will be allocated from the specified heap
- /// </summary>
- /// <param name="heap"><see cref="PrivateHeap"/> to allocate memory from</param>
- /// <exception cref="OutOfMemoryException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- public VnMemoryStream(IUnmangedHeap heap) : this(heap, 0, false) { }
-
- /// <summary>
- /// Creates a new memory stream and pre-allocates the internal
- /// buffer of the specified size on the specified heap to avoid resizing.
- /// </summary>
- /// <param name="heap"><see cref="PrivateHeap"/> to allocate memory from</param>
- /// <param name="bufferSize">Number of bytes (length) of the stream if known</param>
- /// <param name="zero">Zero memory allocations during buffer expansions</param>
- /// <exception cref="OutOfMemoryException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- /// <exception cref="ArgumentOutOfRangeException"></exception>
- public VnMemoryStream(IUnmangedHeap heap, long bufferSize, bool zero)
- {
- _ = heap ?? throw new ArgumentNullException(nameof(heap));
- _buffer = heap.Alloc<byte>(bufferSize, zero);
- }
-
- /// <summary>
- /// Creates a new memory stream from the data provided
- /// </summary>
- /// <param name="heap"><see cref="PrivateHeap"/> to allocate memory from</param>
- /// <param name="data">Initial data</param>
- public VnMemoryStream(IUnmangedHeap heap, ReadOnlySpan<byte> data)
- {
- _ = heap ?? throw new ArgumentNullException(nameof(heap));
- //Alloc the internal buffer to match the data stream
- _buffer = heap.AllocAndCopy(data);
- //Set length
- _length = data.Length;
- //Position will default to 0 cuz its dotnet :P
- return;
- }
-
- /// <summary>
- /// WARNING: Dangerous constructor, make sure read-only and owns hanlde are set accordingly
- /// </summary>
- /// <param name="buffer">The buffer to referrence directly</param>
- /// <param name="length">The length property of the stream</param>
- /// <param name="readOnly">Is the stream readonly (should mostly be true!)</param>
- /// <param name="ownsHandle">Does the new stream own the memory -> <paramref name="buffer"/></param>
- private VnMemoryStream(MemoryHandle<byte> buffer, long length, bool readOnly, bool ownsHandle)
- {
- OwnsHandle = ownsHandle;
- _buffer = buffer; //Consume the handle
- _length = length; //Store length of the buffer
- IsReadonly = readOnly;
- }
-
- /// <summary>
- /// UNSAFE Number of bytes between position and length. Never negative
- /// </summary>
- private long LenToPosDiff => Math.Max(_length - _position, 0);
-
- /// <summary>
- /// If the current stream is a readonly stream, creates an unsafe shallow copy for reading only.
- /// </summary>
- /// <returns>New stream shallow copy of the internal stream</returns>
- /// <exception cref="NotSupportedException"></exception>
- public VnMemoryStream GetReadonlyShallowCopy()
- {
- //Create a new readonly copy (stream does not own the handle)
- return !IsReadonly
- ? throw new NotSupportedException("This stream is not readonly. Cannot create shallow copy on a mutable stream")
- : new VnMemoryStream(_buffer, _length, true, false);
- }
-
- /// <summary>
- /// Writes data directly to the destination stream from the internal buffer
- /// without allocating or copying any data.
- /// </summary>
- /// <param name="destination">The stream to write data to</param>
- /// <param name="bufferSize">The size of the chunks to write to the destination stream</param>
- /// <exception cref="IOException"></exception>
- public override void CopyTo(Stream destination, int bufferSize)
- {
- _ = destination ?? throw new ArgumentNullException(nameof(destination));
-
- if (!destination.CanWrite)
- {
- throw new IOException("The destinaion stream is not writeable");
- }
-
- do
- {
- //Calc the remaining bytes to read no larger than the buffer size
- int bytesToRead = (int)Math.Min(LenToPosDiff, bufferSize);
-
- //Create a span wrapper by using the offet function to support memory handles larger than 2gb
- ReadOnlySpan<byte> span = _buffer.GetOffsetSpan(_position, bytesToRead);
-
- destination.Write(span);
-
- //Update position
- _position += bytesToRead;
-
- } while (LenToPosDiff > 0);
- }
-
- /// <summary>
- /// Allocates a temporary buffer of the desired size, copies data from the internal
- /// buffer and writes it to the destination buffer asynchronously.
- /// </summary>
- /// <param name="destination">The stream to write output data to</param>
- /// <param name="bufferSize">The size of the buffer to use when copying data</param>
- /// <param name="cancellationToken">A token to cancel the opreation</param>
- /// <returns>A task that resolves when the remaining data in the stream has been written to the destination</returns>
- /// <exception cref="IOException"></exception>
- /// <exception cref="ObjectDisposedException"></exception>
- /// <exception cref="ArgumentOutOfRangeException"></exception>
- public override async Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
- {
- _ = destination ?? throw new ArgumentNullException(nameof(destination));
-
- if (!destination.CanWrite)
- {
- throw new IOException("The destinaion stream is not writeable");
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- /*
- * Alloc temp copy buffer. This is a requirement because
- * the stream may be larger than an int32 so it must be
- * copied by segment
- */
-
- using VnTempBuffer<byte> copyBuffer = new(bufferSize);
-
- do
- {
- //read from internal stream
- int read = Read(copyBuffer);
-
- if(read <= 0)
- {
- break;
- }
-
- //write async
- await destination.WriteAsync(copyBuffer.AsMemory(0, read), cancellationToken);
-
- } while (true);
-
- }
-
- /// <summary>
- /// <inheritdoc/>
- /// <para>
- /// This property is always true
- /// </para>
- /// </summary>
- public override bool CanRead => true;
- /// <summary>
- /// <inheritdoc/>
- /// <para>
- /// This propery is always true
- /// </para>
- /// </summary>
- public override bool CanSeek => true;
- /// <summary>
- /// True unless the stream is (or has been converted to) a readonly
- /// stream.
- /// </summary>
- public override bool CanWrite => !IsReadonly;
- ///<inheritdoc/>
- public override long Length => _length;
- ///<inheritdoc/>
- public override bool CanTimeout => false;
-
- ///<inheritdoc/>
- public override long Position
- {
- get => _position;
- set => Seek(value, SeekOrigin.Begin);
- }
- /// <summary>
- /// Closes the stream and frees the internal allocated memory blocks
- /// </summary>
- public override void Close()
- {
- //Only dispose buffer if we own it
- if (OwnsHandle)
- {
- _buffer.Dispose();
- }
- }
- ///<inheritdoc/>
- public override void Flush() { }
- // Override to reduce base class overhead
- ///<inheritdoc/>
- public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask;
- ///<inheritdoc/>
- public override int Read(byte[] buffer, int offset, int count) => Read(new Span<byte>(buffer, offset, count));
- ///<inheritdoc/>
- public override int Read(Span<byte> destination)
- {
- if (destination.Length == 0)
- {
- return 0;
- }
- //Number of bytes to read from memory buffer
- int bytesToRead = checked((int)Math.Min(LenToPosDiff, destination.Length));
- //Copy bytes to buffer
- Memory.Copy(_buffer, _position, destination, 0, bytesToRead);
- //Increment buffer position
- _position += bytesToRead;
- //Bytestoread should never be larger than int.max because span length is an integer
- return bytesToRead;
- }
-
- /*
- * Async reading will always run synchronously in a memory stream,
- * so overrides are just so avoid base class overhead
- */
- ///<inheritdoc/>
- public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
- {
- //Read synchronously and return a completed task
- int read = Read(buffer.Span);
- return ValueTask.FromResult(read);
- }
- ///<inheritdoc/>
- public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- //Read synchronously and return a completed task
- int read = Read(buffer.AsSpan(offset, count));
- return Task.FromResult(read);
- }
- ///<inheritdoc/>
- public override long Seek(long offset, SeekOrigin origin)
- {
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(offset), "Offset cannot be less than 0");
- }
- switch (origin)
- {
- case SeekOrigin.Begin:
- //Length will never be greater than int.Max so output will never exceed int.max
- _position = Math.Min(_length, offset);
- return _position;
- case SeekOrigin.Current:
- long newPos = _position + offset;
- //Length will never be greater than int.Max so output will never exceed length
- _position = Math.Min(_length, newPos);
- return newPos;
- case SeekOrigin.End:
- long real_index = _length - offset;
- //If offset moves the position negative, just set the position to 0 and continue
- _position = Math.Min(real_index, 0);
- return real_index;
- default:
- throw new ArgumentException("Stream operation is not supported on current stream");
- }
- }
-
-
- /// <summary>
- /// Resizes the internal buffer to the exact size (in bytes) of the
- /// value argument. A value of 0 will free the entire buffer. A value
- /// greater than zero will resize the buffer (and/or alloc)
- /// </summary>
- /// <param name="value">The size of the stream (and internal buffer)</param>
- /// <exception cref="OutOfMemoryException"></exception>
- /// <exception cref="NotSupportedException"></exception>
- /// <exception cref="ObjectDisposedException"></exception>
- /// <exception cref="ArgumentOutOfRangeException"></exception>
- public override void SetLength(long value)
- {
- if (IsReadonly)
- {
- throw new NotSupportedException("This stream is readonly");
- }
- if (value < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(value), "Value cannot be less than 0");
- }
- //Resize the buffer to the specified length
- _buffer.Resize(value);
- //Set length
- _length = value;
- //Make sure the position is not pointing outside of the buffer
- _position = Math.Min(_position, _length);
- return;
- }
- ///<inheritdoc/>
- public override void Write(byte[] buffer, int offset, int count) => Write(new ReadOnlySpan<byte>(buffer, offset, count));
- ///<inheritdoc/>
- public override void Write(ReadOnlySpan<byte> buffer)
- {
- if (IsReadonly)
- {
- throw new NotSupportedException("Write operation is not allowed on readonly stream!");
- }
- //Calculate the new final position
- long newPos = (_position + buffer.Length);
- //Determine if the buffer needs to be expanded
- if (buffer.Length > LenToPosDiff)
- {
- //Expand buffer if required
- _buffer.ResizeIfSmaller(newPos);
- //Update length
- _length = newPos;
- }
- //Copy the input buffer to the internal buffer
- Memory.Copy(buffer, _buffer, _position);
- //Update the position
- _position = newPos;
- return;
- }
- ///<inheritdoc/>
- public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- //Write synchronously and return a completed task
- Write(buffer, offset, count);
- return Task.CompletedTask;
- }
- ///<inheritdoc/>
- public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
- {
- //Write synchronously and return a completed task
- Write(buffer.Span);
- return ValueTask.CompletedTask;
- }
- ///<inheritdoc/>
- public override void WriteByte(byte value)
- {
- Span<byte> buf = MemoryMarshal.CreateSpan(ref value, 1);
- Write(buf);
- }
-
- /// <summary>
- /// Allocates and copies internal buffer to new managed byte[]
- /// </summary>
- /// <returns>Copy of internal buffer</returns>
- /// <exception cref="OutOfMemoryException"></exception>
- /// <exception cref="OutOfMemoryException"></exception>
- public byte[] ToArray()
- {
- //Alloc a new array of the size of the internal buffer
- byte[] data = new byte[_length];
- //Copy data from the internal buffer to the output buffer
- _buffer.Span.CopyTo(data);
- return data;
-
- }
- /// <summary>
- /// Returns a <see cref="ReadOnlySpan{T}"/> window over the data within the entire stream
- /// </summary>
- /// <returns>A <see cref="ReadOnlySpan{T}"/> of the data within the entire stream</returns>
- /// <exception cref="OverflowException"></exception>
- public ReadOnlySpan<byte> AsSpan()
- {
- ReadOnlySpan<byte> output = _buffer.Span;
- return output[..(int)_length];
- }
-
- /// <summary>
- /// If the current stream is a readonly stream, creates a shallow copy for reading only.
- /// </summary>
- /// <returns>New stream shallow copy of the internal stream</returns>
- /// <exception cref="InvalidOperationException"></exception>
- public object Clone() => GetReadonlyShallowCopy();
-
- /*
- * Override the Dispose async method to avoid the base class overhead
- * and task allocation since this will always be a syncrhonous
- * operation (freeing memory)
- */
-
- ///<inheritdoc/>
- public override ValueTask DisposeAsync()
- {
- //Dispose and return completed task
- base.Dispose(true);
- GC.SuppressFinalize(this);
- return ValueTask.CompletedTask;
- }
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/VnStreamReader.cs b/Utils/src/IO/VnStreamReader.cs
deleted file mode 100644
index 70b9734..0000000
--- a/Utils/src/IO/VnStreamReader.cs
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: VnStreamReader.cs
-*
-* VnStreamReader.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.Text;
-using System.Buffers;
-using System.Threading;
-using System.Threading.Tasks;
-
-using VNLib.Utils.Extensions;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// Binary based buffered text reader, optimized for reading network streams
- /// </summary>
- public class VnStreamReader : TextReader, IVnTextReader
- {
- private bool disposedValue;
-
- private readonly ISlindingWindowBuffer<byte> _buffer;
- ///<inheritdoc/>
- public virtual Stream BaseStream { get; }
- ///<inheritdoc/>
- public Encoding Encoding { get; }
-
- /// <summary>
- /// Number of available bytes of buffered data within the current buffer window
- /// </summary>
- public int Available => _buffer.AccumulatedSize;
- /// <summary>
- /// Gets or sets the line termination used to deliminate a line of data
- /// </summary>
- public ReadOnlyMemory<byte> LineTermination { get; set; }
- Span<byte> IVnTextReader.BufferedDataWindow => _buffer.Accumulated;
-
- /// <summary>
- /// Creates a new <see cref="TextReader"/> that reads encoded data from the base.
- /// Internal buffers will be alloced from <see cref="ArrayPool{T}.Shared"/>
- /// </summary>
- /// <param name="baseStream">The underlying stream to read data from</param>
- /// <param name="enc">The <see cref="Encoding"/> to use when reading from the stream</param>
- /// <param name="bufferSize">The size of the internal binary buffer</param>
- public VnStreamReader(Stream baseStream, Encoding enc, int bufferSize)
- {
- BaseStream = baseStream;
- Encoding = enc;
- //Init a new buffer
- _buffer = InitializeBuffer(bufferSize);
- }
-
- /// <summary>
- /// Invoked by the constuctor method to allocte the internal buffer with the specified buffer size.
- /// </summary>
- /// <param name="bufferSize">The requested size of the buffer to alloc</param>
- /// <remarks>By default requests the buffer from the <see cref="ArrayPool{T}.Shared"/> instance</remarks>
- protected virtual ISlindingWindowBuffer<byte> InitializeBuffer(int bufferSize) => new ArrayPoolStreamBuffer<byte>(ArrayPool<byte>.Shared, bufferSize);
-
- ///<inheritdoc/>
- public override async Task<string?> ReadLineAsync()
- {
- //If buffered data is available, check for line termination
- if (Available > 0)
- {
- //Get current buffer window
- Memory<byte> buffered = _buffer.AccumulatedBuffer;
- //search for line termination in current buffer
- int term = buffered.IndexOf(LineTermination);
- //Termination found in buffer window
- if (term > -1)
- {
- //Capture the line from the begining of the window to the termination
- Memory<byte> line = buffered[..term];
- //Shift the window to the end of the line (excluding the termination)
- _buffer.AdvanceStart(term + LineTermination.Length);
- //Decode the line to a string
- return Encoding.GetString(line.Span);
- }
- //Termination not found
- }
- //Compact the buffer window and see if space is avialble to buffer more data
- if (_buffer.CompactBufferWindow())
- {
- //There is room, so buffer more data
- await _buffer.AccumulateDataAsync(BaseStream, CancellationToken.None);
- //Check again to see if more data is buffered
- if (Available <= 0)
- {
- //No string found
- return null;
- }
- //Get current buffer window
- Memory<byte> buffered = _buffer.AccumulatedBuffer;
- //search for line termination in current buffer
- int term = buffered.IndexOf(LineTermination);
- //Termination found in buffer window
- if (term > -1)
- {
- //Capture the line from the begining of the window to the termination
- Memory<byte> line = buffered[..term];
- //Shift the window to the end of the line (excluding the termination)
- _buffer.AdvanceStart(term + LineTermination.Length);
- //Decode the line to a string
- return Encoding.GetString(line.Span);
- }
- }
- //Termination not found within the entire buffer, so buffer space has been exhausted
-
- //OOM is raised in the TextReader base class, the standard is preserved
-#pragma warning disable CA2201 // Do not raise reserved exception types
- throw new OutOfMemoryException("A line termination was not found within the buffer");
-#pragma warning restore CA2201 // Do not raise reserved exception types
- }
-
- ///<inheritdoc/>
- public override int Read(char[] buffer, int index, int count) => Read(buffer.AsSpan(index, count));
- ///<inheritdoc/>
- public override int Read(Span<char> buffer)
- {
- if (Available <= 0)
- {
- return 0;
- }
- //Get current buffer window
- Span<byte> buffered = _buffer.Accumulated;
- //Convert all avialable data
- int encoded = Encoding.GetChars(buffered, buffer);
- //Shift buffer window to the end of the converted data
- _buffer.AdvanceStart(encoded);
- //return the number of chars written
- return Encoding.GetCharCount(buffered);
- }
- ///<inheritdoc/>
- public override void Close() => _buffer.Close();
- ///<inheritdoc/>
- protected override void Dispose(bool disposing)
- {
- if (!disposedValue)
- {
- Close();
- disposedValue = true;
- }
- base.Dispose(disposing);
- }
-
- /// <summary>
- /// Resets the internal buffer window
- /// </summary>
- protected void ClearBuffer()
- {
- _buffer.Reset();
- }
-
- void IVnTextReader.Advance(int count) => _buffer.AdvanceStart(count);
- void IVnTextReader.FillBuffer() => _buffer.AccumulateData(BaseStream);
- ERRNO IVnTextReader.CompactBufferWindow() => _buffer.CompactBufferWindow();
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/VnStreamWriter.cs b/Utils/src/IO/VnStreamWriter.cs
deleted file mode 100644
index 37d700c..0000000
--- a/Utils/src/IO/VnStreamWriter.cs
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: VnStreamWriter.cs
-*
-* VnStreamWriter.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.Text;
-using System.Buffers;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Runtime.InteropServices;
-using System.Runtime.CompilerServices;
-
-using VNLib.Utils.Memory;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// Provides a memory optimized <see cref="TextWriter"/> implementation. Optimized for writing
- /// to network streams
- /// </summary>
- public class VnStreamWriter : TextWriter
- {
- private readonly Encoder Enc;
-
- private readonly ISlindingWindowBuffer<byte> _buffer;
-
- private bool closed;
-
- /// <summary>
- /// Gets the underlying stream that interfaces with the backing store
- /// </summary>
- public virtual Stream BaseStream { get; }
- ///<inheritdoc/>
- public override Encoding Encoding { get; }
-
- /// <summary>
- /// Line termination to use when writing lines to the output
- /// </summary>
- public ReadOnlyMemory<byte> LineTermination { get; set; }
- ///<inheritdoc/>
- public override string NewLine
- {
- get => Encoding.GetString(LineTermination.Span);
- set => LineTermination = Encoding.GetBytes(value);
- }
-
- /// <summary>
- /// Creates a new <see cref="VnStreamWriter"/> that writes formatted data
- /// to the specified base stream
- /// </summary>
- /// <param name="baseStream">The stream to write data to</param>
- /// <param name="encoding">The <see cref="Encoding"/> to use when writing data</param>
- /// <param name="bufferSize">The size of the internal buffer used to buffer binary data before writing to the base stream</param>
- public VnStreamWriter(Stream baseStream, Encoding encoding, int bufferSize = 1024)
- {
- //Store base stream
- BaseStream = baseStream;
- Encoding = encoding;
- //Get an encoder
- Enc = encoding.GetEncoder();
- _buffer = InitializeBuffer(bufferSize);
- }
-
- /// <summary>
- /// Invoked by the constuctor method to allocte the internal buffer with the specified buffer size.
- /// </summary>
- /// <param name="bufferSize">The requested size of the buffer to alloc</param>
- /// <remarks>By default requests the buffer from the <see cref="MemoryPool{T}.Shared"/> instance</remarks>
- protected virtual ISlindingWindowBuffer<byte> InitializeBuffer(int bufferSize) => new ArrayPoolStreamBuffer<byte>(ArrayPool<byte>.Shared, bufferSize);
- ///<inheritdoc/>
- public void Write(byte value)
- {
- //See if there is room in the binary buffer
- if (_buffer.AccumulatedSize == 0)
- {
- //There is not enough room to store the single byte
- Flush();
- }
- //Store at the end of the window
- _buffer.Append(value);
- }
- ///<inheritdoc/>
- public override void Write(char value)
- {
- ReadOnlySpan<char> tbuf = MemoryMarshal.CreateSpan(ref value, 0x01);
- Write(tbuf);
- }
- ///<inheritdoc/>
- public override void Write(object value) => Write(value.ToString());
- ///<inheritdoc/>
- public override void Write(string value) => Write(value.AsSpan());
- ///<inheritdoc/>
- public override void Write(ReadOnlySpan<char> buffer)
- {
- Check();
-
- ForwardOnlyReader<char> reader = new(buffer);
-
- //Create a variable for a character buffer window
- bool completed;
- do
- {
- //Get an available buffer window to store characters in and convert the characters to binary
- Enc.Convert(reader.Window, _buffer.Remaining, true, out int charsUsed, out int bytesUsed, out completed);
- //Update byte position
- _buffer.Advance(bytesUsed);
- //Update char position
- reader.Advance(charsUsed);
-
- //Converting did not complete because the buffer was too small
- if (!completed || reader.WindowSize == 0)
- {
- //Flush the buffer and continue
- Flush();
- }
-
- } while (!completed);
- //Reset the encoder
- Enc.Reset();
- }
- ///<inheritdoc/>
- public override async Task WriteAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken = default)
- {
- Check();
- //Create a variable for a character buffer window
- bool completed;
- ForwardOnlyMemoryReader<char> reader = new(buffer);
- do
- {
- //Get an available buffer window to store characters in and convert the characters to binary
- Enc.Convert(reader.Window.Span, _buffer.Remaining, true, out int charsUsed, out int bytesUsed, out completed);
- //Update byte position
- _buffer.Advance(bytesUsed);
- //Update char position
- reader.Advance(charsUsed);
- //Converting did not complete because the buffer was too small
- if (!completed || reader.WindowSize == 0)
- {
- //Flush the buffer and continue
- await FlushWriterAsync(cancellationToken);
- }
- } while (!completed);
- //Reset the encoder
- Enc.Reset();
- }
-
- ///<inheritdoc/>
- public override void WriteLine()
- {
- Check();
- //See if there is room in the binary buffer
- if (_buffer.RemainingSize < LineTermination.Length)
- {
- //There is not enough room to store the termination, so we need to flush the buffer
- Flush();
- }
- _buffer.Append(LineTermination.Span);
- }
- ///<inheritdoc/>
- public override void WriteLine(object value) => WriteLine(value.ToString());
- ///<inheritdoc/>
- public override void WriteLine(string value) => WriteLine(value.AsSpan());
- ///<inheritdoc/>
- public override void WriteLine(ReadOnlySpan<char> buffer)
- {
- //Write the value itself
- Write(buffer);
- //Write the line termination
- WriteLine();
- }
-
- ///<inheritdoc/>
- ///<exception cref="ObjectDisposedException"></exception>
- public override void Flush()
- {
- Check();
- //If data is available to be written, write it to the base stream
- if (_buffer.AccumulatedSize > 0)
- {
- //Write all buffered data to stream
- BaseStream.Write(_buffer.Accumulated);
- //Reset the buffer
- _buffer.Reset();
- }
- }
- /// <summary>
- /// Asynchronously flushes the internal buffers to the <see cref="BaseStream"/>, and resets the internal buffer state
- /// </summary>
- /// <returns>A <see cref="ValueTask"/> that represents the asynchronous flush operation</returns>
- /// <exception cref="ObjectDisposedException"></exception>
- public async ValueTask FlushWriterAsync(CancellationToken cancellationToken = default)
- {
- Check();
- if (_buffer.AccumulatedSize > 0)
- {
- //Flush current window to the stream
- await BaseStream.WriteAsync(_buffer.AccumulatedBuffer, cancellationToken);
- //Reset the buffer
- _buffer.Reset();
- }
- }
-
- ///<inheritdoc/>
- public override Task FlushAsync() => FlushWriterAsync().AsTask();
-
- /// <summary>
- /// Resets internal properies for resuse
- /// </summary>
- protected void Reset()
- {
- _buffer.Reset();
- Enc.Reset();
- }
- ///<inheritdoc/>
- public override void Close()
- {
- //Only invoke close once
- if (closed)
- {
- return;
- }
- try
- {
- Flush();
- }
- finally
- {
- //Release the memory handle if its set
- _buffer.Close();
- //Set closed flag
- closed = true;
- }
- }
- ///<inheritdoc/>
- protected override void Dispose(bool disposing)
- {
- Close();
- base.Dispose(disposing);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void Check()
- {
- if (closed)
- {
- throw new ObjectDisposedException("The stream is closed");
- }
- }
- ///<inheritdoc/>
- public override async ValueTask DisposeAsync()
- {
- //Only invoke close once
- if (closed)
- {
- return;
- }
- try
- {
- await FlushWriterAsync();
- }
- finally
- {
- //Set closed flag
- closed = true;
- //Release the memory handle if its set
- _buffer.Close();
- }
- GC.SuppressFinalize(this);
- }
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/VnTextReaderExtensions.cs b/Utils/src/IO/VnTextReaderExtensions.cs
deleted file mode 100644
index 119461b..0000000
--- a/Utils/src/IO/VnTextReaderExtensions.cs
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: VnTextReaderExtensions.cs
-*
-* VnTextReaderExtensions.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-
-using VNLib.Utils.Extensions;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// Extension methods to help reuse code for used TextReader implementations
- /// </summary>
- public static class VnTextReaderExtensions
- {
- public const int E_BUFFER_TOO_SMALL = -1;
-
-
- /*
- * Generic extensions provide constained compiler method invocation
- * for structs the implement the IVNtextReader
- */
-
- /// <summary>
- /// Attempts to read a line from the stream and store it in the specified buffer
- /// </summary>
- /// <param name="reader"></param>
- /// <param name="charBuffer">The character buffer to write data to</param>
- /// <returns>Returns the number of bytes read, <see cref="E_BUFFER_TOO_SMALL"/>
- /// if the buffer was not large enough, 0 if no data was available</returns>
- /// <exception cref="OutOfMemoryException"></exception>
- /// <remarks>Allows reading lines of data from the stream without allocations</remarks>
- public static ERRNO ReadLine<T>(this ref T reader, Span<char> charBuffer) where T:struct, IVnTextReader
- {
- return readLine(ref reader, charBuffer);
- }
- /// <summary>
- /// Attempts to read a line from the stream and store it in the specified buffer
- /// </summary>
- /// <param name="reader"></param>
- /// <param name="charBuffer">The character buffer to write data to</param>
- /// <returns>Returns the number of bytes read, <see cref="E_BUFFER_TOO_SMALL"/>
- /// if the buffer was not large enough, 0 if no data was available</returns>
- /// <exception cref="OutOfMemoryException"></exception>
- /// <remarks>Allows reading lines of data from the stream without allocations</remarks>
- public static ERRNO ReadLine<T>(this T reader, Span<char> charBuffer) where T : class, IVnTextReader
- {
- return readLine(ref reader, charBuffer);
- }
-
- /// <summary>
- /// Fill a buffer with reamining buffered data
- /// </summary>
- /// <param name="reader"></param>
- /// <param name="buffer">Buffer to copy data to</param>
- /// <param name="offset">Offset in buffer to begin writing</param>
- /// <param name="count">Number of bytes to read</param>
- /// <returns>The number of bytes copied to the input buffer</returns>
- public static int ReadRemaining<T>(this ref T reader, byte[] buffer, int offset, int count) where T : struct, IVnTextReader
- {
- return reader.ReadRemaining(buffer.AsSpan(offset, count));
- }
- /// <summary>
- /// Fill a buffer with reamining buffered data
- /// </summary>
- /// <param name="reader"></param>
- /// <param name="buffer">Buffer to copy data to</param>
- /// <param name="offset">Offset in buffer to begin writing</param>
- /// <param name="count">Number of bytes to read</param>
- /// <returns>The number of bytes copied to the input buffer</returns>
- public static int ReadRemaining<T>(this T reader, byte[] buffer, int offset, int count) where T : class, IVnTextReader
- {
- return reader.ReadRemaining(buffer.AsSpan(offset, count));
- }
-
- /// <summary>
- /// Fill a buffer with reamining buffered data, up to
- /// the size of the supplied buffer
- /// </summary>
- /// <param name="reader"></param>
- /// <param name="buffer">Buffer to copy data to</param>
- /// <returns>The number of bytes copied to the input buffer</returns>
- /// <remarks>You should use the <see cref="IVnTextReader.Available"/> property to know how much remaining data is buffered</remarks>
- public static int ReadRemaining<T>(this ref T reader, Span<byte> buffer) where T : struct, IVnTextReader
- {
- return readRemaining(ref reader, buffer);
- }
- /// <summary>
- /// Fill a buffer with reamining buffered data, up to
- /// the size of the supplied buffer
- /// </summary>
- /// <param name="reader"></param>
- /// <param name="buffer">Buffer to copy data to</param>
- /// <returns>The number of bytes copied to the input buffer</returns>
- /// <remarks>You should use the <see cref="IVnTextReader.Available"/> property to know how much remaining data is buffered</remarks>
- public static int ReadRemaining<T>(this T reader, Span<byte> buffer) where T : class, IVnTextReader
- {
- return readRemaining(ref reader, buffer);
- }
-
- private static ERRNO readLine<T>(ref T reader, Span<char> chars) where T: IVnTextReader
- {
- /*
- * I am aware of a potential bug, the line decoding process
- * shifts the interal buffer by the exact number of bytes to
- * the end of the line, without considering if the decoder failed
- * to properly decode the entire line.
- *
- * I dont expect this to be an issue unless there is a bug within the specified
- * encoder implementation
- */
- ReadOnlySpan<byte> LineTermination = reader.LineTermination.Span;
- //If buffered data is available, check for line termination
- if (reader.Available > 0)
- {
- //Get current buffer window
- ReadOnlySpan<byte> bytes = reader.BufferedDataWindow;
- //search for line termination in current buffer
- int term = bytes.IndexOf(LineTermination);
- //Termination found in buffer window
- if (term > -1)
- {
- //Capture the line from the begining of the window to the termination
- ReadOnlySpan<byte> line = bytes[..term];
- //Get the number ot chars
- int charCount = reader.Encoding.GetCharCount(line);
- //See if the buffer is large enough
- if (bytes.Length < charCount)
- {
- return E_BUFFER_TOO_SMALL;
- }
- //Use the decoder to convert the data
- _ = reader.Encoding.GetChars(line, chars);
- //Shift the window to the end of the line (excluding the termination, regardless of the conversion result)
- reader.Advance(term + LineTermination.Length);
- //Return the number of characters
- return charCount;
- }
- //Termination not found but there may be more data waiting
- }
- //Compact the buffer window and make sure it was compacted so there is room to fill the buffer
- if (reader.CompactBufferWindow())
- {
- //There is room, so buffer more data
- reader.FillBuffer();
- //Check again to see if more data is buffered
- if (reader.Available <= 0)
- {
- //No data avialable
- return 0;
- }
- //Get current buffer window
- ReadOnlySpan<byte> bytes = reader.BufferedDataWindow;
- //search for line termination in current buffer
- int term = bytes.IndexOf(LineTermination);
- //Termination found in buffer window
- if (term > -1)
- {
- //Capture the line from the begining of the window to the termination
- ReadOnlySpan<byte> line = bytes[..term];
- //Get the number ot chars
- int charCount = reader.Encoding.GetCharCount(line);
- //See if the buffer is large enough
- if (bytes.Length < charCount)
- {
- return E_BUFFER_TOO_SMALL;
- }
- //Use the decoder to convert the data
- _ = reader.Encoding.GetChars(line, chars);
- //Shift the window to the end of the line (excluding the termination, regardless of the conversion result)
- reader.Advance(term + LineTermination.Length);
- //Return the number of characters
- return charCount;
- }
- }
-
- //Termination not found within the entire buffer, so buffer space has been exhausted
-
- //Supress as this response is expected when the buffer is exhausted,
-#pragma warning disable CA2201 // Do not raise reserved exception types
- throw new OutOfMemoryException("The line was not found within the current buffer, cannot continue");
-#pragma warning restore CA2201 // Do not raise reserved exception types
- }
-
- private static int readRemaining<T>(ref T reader, Span<byte> buffer) where T: IVnTextReader
- {
- //guard for empty buffer
- if (buffer.Length == 0 || reader.Available == 0)
- {
- return 0;
- }
- //get the remaining bytes in the reader
- Span<byte> remaining = reader.BufferedDataWindow;
- //Calculate the number of bytes to copy
- int canCopy = Math.Min(remaining.Length, buffer.Length);
- //Copy remaining bytes to buffer
- remaining[..canCopy].CopyTo(buffer);
- //Shift the window by the number of bytes copied
- reader.Advance(canCopy);
- return canCopy;
- }
- }
-} \ No newline at end of file
diff --git a/Utils/src/IO/WriteOnlyBufferedStream.cs b/Utils/src/IO/WriteOnlyBufferedStream.cs
deleted file mode 100644
index 5e7faa1..0000000
--- a/Utils/src/IO/WriteOnlyBufferedStream.cs
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: WriteOnlyBufferedStream.cs
-*
-* WriteOnlyBufferedStream.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils 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
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.Buffers;
-using System.Threading;
-using System.Threading.Tasks;
-
-using VNLib.Utils.Memory;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// A basic accumulator style write buffered stream
- /// </summary>
- public class WriteOnlyBufferedStream : Stream
- {
- private readonly ISlindingWindowBuffer<byte> _buffer;
- private readonly bool LeaveOpen;
-
- /// <summary>
- /// Gets the underlying stream that interfaces with the backing store
- /// </summary>
- public Stream BaseStream { get; init; }
-
- /// <summary>
- /// Initalizes a new <see cref="WriteOnlyBufferedStream"/> using the
- /// specified backing stream, using the specified buffer size, and
- /// optionally leaves the stream open
- /// </summary>
- /// <param name="baseStream">The backing stream to write buffered data to</param>
- /// <param name="bufferSize">The size of the internal buffer</param>
- /// <param name="leaveOpen">A value indicating of the stream should be left open when the buffered stream is closed</param>
- public WriteOnlyBufferedStream(Stream baseStream, int bufferSize, bool leaveOpen = false)
- {
- BaseStream = baseStream;
- //Create buffer
- _buffer = InitializeBuffer(bufferSize);
- LeaveOpen = leaveOpen;
- }
- /// <summary>
- /// Invoked by the constuctor method to allocte the internal buffer with the specified buffer size.
- /// </summary>
- /// <param name="bufferSize">The requested size of the buffer to alloc</param>
- /// <remarks>By default requests the buffer from the <see cref="ArrayPool{T}.Shared"/> instance</remarks>
- protected virtual ISlindingWindowBuffer<byte> InitializeBuffer(int bufferSize)
- {
- return new ArrayPoolStreamBuffer<byte>(ArrayPool<byte>.Shared, bufferSize);
- }
-
- ///<inheritdoc/>
- public override void Close()
- {
- try
- {
- //Make sure the buffer is empty
- WriteBuffer();
-
- if (!LeaveOpen)
- {
- //Dispose stream
- BaseStream.Dispose();
- }
- }
- finally
- {
- _buffer.Close();
- }
- }
- ///<inheritdoc/>
- public override async ValueTask DisposeAsync()
- {
- try
- {
- if (_buffer.AccumulatedSize > 0)
- {
- await WriteBufferAsync(CancellationToken.None);
- }
-
- if (!LeaveOpen)
- {
- //Dispose stream
- await BaseStream.DisposeAsync();
- }
-
- GC.SuppressFinalize(this);
- }
- finally
- {
- _buffer.Close();
- }
- }
-
- ///<inheritdoc/>
- public override void Flush() => WriteBuffer();
- ///<inheritdoc/>
- public override Task FlushAsync(CancellationToken cancellationToken) => WriteBufferAsync(cancellationToken).AsTask();
-
- private void WriteBuffer()
- {
- //Only if data is available to write
- if (_buffer.AccumulatedSize > 0)
- {
- //Write data to stream
- BaseStream.Write(_buffer.Accumulated);
- //Reset position
- _buffer.Reset();
- }
- }
-
- private async ValueTask WriteBufferAsync(CancellationToken token = default)
- {
- if(_buffer.AccumulatedSize > 0)
- {
- await BaseStream.WriteAsync(_buffer.AccumulatedBuffer, token);
- _buffer.Reset();
- }
- }
- ///<inheritdoc/>
- public override void Write(byte[] buffer, int offset, int count) => Write(buffer.AsSpan(offset, count));
-
- public override void Write(ReadOnlySpan<byte> buffer)
- {
- ForwardOnlyReader<byte> reader = new(buffer);
- //Attempt to buffer/flush data until all data is sent
- do
- {
- //Try to buffer as much as possible
- ERRNO buffered = _buffer.TryAccumulate(reader.Window);
-
- if(buffered < reader.WindowSize)
- {
- //Buffer is full and needs to be flushed
- WriteBuffer();
- //Advance reader and continue to buffer
- reader.Advance(buffered);
- continue;
- }
-
- break;
- }
- while (true);
- }
-
- public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- return WriteAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask();
- }
-
- public async override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
- {
- ForwardOnlyMemoryReader<byte> reader = new(buffer);
- //Attempt to buffer/flush data until all data is sent
- do
- {
- //Try to buffer as much as possible
- ERRNO buffered = _buffer.TryAccumulate(reader.Window.Span);
-
- if (buffered < reader.WindowSize)
- {
- //Buffer is full and needs to be flushed
- await WriteBufferAsync(cancellationToken);
- //Advance reader and continue to buffer
- reader.Advance(buffered);
- continue;
- }
-
- break;
- }
- while (true);
- }
-
-
- /// <summary>
- /// Always false
- /// </summary>
- public override bool CanRead => false;
- /// <summary>
- /// Always returns false
- /// </summary>
- public override bool CanSeek => false;
- /// <summary>
- /// Always true
- /// </summary>
- public override bool CanWrite => true;
- /// <summary>
- /// Returns the size of the underlying buffer
- /// </summary>
- public override long Length => _buffer.AccumulatedSize;
- /// <summary>
- /// Always throws <see cref="NotSupportedException"/>
- /// </summary>
- /// <exception cref="NotSupportedException"></exception>
- public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
- /// <summary>
- /// Always throws <see cref="NotSupportedException"/>
- /// </summary>
- /// <exception cref="NotSupportedException"></exception>
- /// <returns></returns>
- public override int Read(byte[] buffer, int offset, int count)
- {
- throw new NotSupportedException("This stream is not readable");
- }
-
- /// <summary>
- /// Always throws <see cref="NotSupportedException"/>
- /// </summary>
- /// <exception cref="NotSupportedException"></exception>
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotSupportedException();
- }
-
- /// <summary>
- /// Always throws <see cref="NotSupportedException"/>
- /// </summary>
- /// <exception cref="NotSupportedException"></exception>
- public override void SetLength(long value)
- {
- throw new NotSupportedException();
- }
-
- public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- throw new NotImplementedException();
- }
-
- public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
- {
- throw new NotImplementedException();
- }
- }
-}