Skip to content

Commit

Permalink
Merge branch 'feature/2.2.0-2025q1'
Browse files Browse the repository at this point in the history
  • Loading branch information
dudinda committed Jan 16, 2025
2 parents a7e6c7c + ed3c6e0 commit 2695826
Show file tree
Hide file tree
Showing 16 changed files with 280 additions and 145 deletions.
5 changes: 3 additions & 2 deletions ExtSort/Code/Extensions/StreamExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ internal static class StreamExtensions
public static void SkipPreamble(this StreamWriter writer)
{
var tmp = writer.AutoFlush;
writer.AutoFlush = false;
writer.BaseStream.Position = 0;
writer.AutoFlush = true;
if (writer.BaseStream.Position > 0)
writer.BaseStream.Position = 0;
writer.AutoFlush = tmp;
}
}
Expand Down
156 changes: 73 additions & 83 deletions ExtSort/Code/Streams/StreamReaderWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@

namespace ExtSort.Code.Streams
{
/// <summary>
/// Wrapper around the <see cref="StreamReader"/> to allow read
/// lines as the Span or as the Memory of type char
/// </summary>
public class StreamReaderWrapper : TextReader
{
#region StreamReader Implementation
// Using a 1K byte buffer and a 4K FileStream buffer works out pretty well
// perf-wise. On even a 40 MB text file, any perf loss by using a 4K
// buffer is negated by the win of allocating a smaller byte[], which
Expand Down Expand Up @@ -594,34 +599,80 @@ private void ThrowIfDisposed()
void ThrowObjectDisposedException() => throw new ObjectDisposedException(GetType().Name);
}

public Memory<char> ReadLineAsMemory()
private static Stream ValidateArgsAndOpenPath(string path, Encoding encoding, FileStreamOptions options)
{
ThrowIfDisposed();
ValidateArgs(path, encoding);

if (_charPos == _charLen)
if (options is null)
{
if (ReadBuffer() == 0)
throw new ArgumentNullException(nameof(options));
}
if ((options.Access & FileAccess.Read) == 0)
{
throw new ArgumentException(nameof(options));
}

return new FileStream(path, options);
}

private static Stream ValidateArgsAndOpenPath(string path, Encoding encoding, int bufferSize)
{
ValidateArgs(path, encoding);
if (bufferSize <= 0)
throw new ArgumentOutOfRangeException(nameof(bufferSize));

return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultFileStreamBufferSize);
}

private static void ValidateArgs(string path, Encoding encoding)
{
if (path == null)
throw new ArgumentNullException(nameof(path));
if (encoding == null)
throw new ArgumentNullException(nameof(encoding));
if (path.Length == 0)
throw new ArgumentException();
}

public bool EndOfStream
{
get
{
ThrowIfDisposed();

if (_charPos < _charLen)
{
return false;
}

// This may block on pipes!
int numRead = ReadBuffer();
return numRead == 0;
}
}

#endregion

public Memory<char> ReadLineAsMemory() {
ThrowIfDisposed();

if (_charPos == _charLen) {
if (ReadBuffer() == 0) {
return null;
}
}

do
{
do {
int i = _charPos;
do
{
do {
char ch = _charBuffer[i];
// Note the following common line feed chars:
// \n - UNIX \r\n - DOS \r - Mac
if (ch == '\r' || ch == '\n')
{
if (ch == '\r' || ch == '\n') {
var result = _charBuffer.AsMemory().Slice(_charPos, i - _charPos);
_charPos = i + 1;
if (ch == '\r' && (_charPos < _charLen || ReadBuffer() > 0))
{
if (_charBuffer[_charPos] == '\n')
{
if (ch == '\r' && (_charPos < _charLen || ReadBuffer() > 0)) {
if (_charBuffer[_charPos] == '\n') {
_charPos++;
}
}
Expand All @@ -636,34 +687,26 @@ public Memory<char> ReadLineAsMemory()
return _charBuffer.AsMemory();
}

public Span<char> ReadLineAsSpan()
{
public Span<char> ReadLineAsSpan() {
ThrowIfDisposed();

if (_charPos == _charLen)
{
if (ReadBuffer() == 0)
{
if (_charPos == _charLen) {
if (ReadBuffer() == 0) {
return null;
}
}

do
{
do {
int i = _charPos;
do
{
do {
char ch = _charBuffer[i];
// Note the following common line feed chars:
// \n - UNIX \r\n - DOS \r - Mac
if (ch == '\r' || ch == '\n')
{
if (ch == '\r' || ch == '\n') {
var result = _charBuffer.AsSpan().Slice(_charPos, i - _charPos);
_charPos = i + 1;
if (ch == '\r' && (_charPos < _charLen || ReadBuffer() > 0))
{
if (_charBuffer[_charPos] == '\n')
{
if (ch == '\r' && (_charPos < _charLen || ReadBuffer() > 0)) {
if (_charBuffer[_charPos] == '\n') {
_charPos++;
}
}
Expand All @@ -677,58 +720,5 @@ public Span<char> ReadLineAsSpan()
} while (ReadBuffer() > 0);
return _charBuffer.AsSpan();
}

private static Stream ValidateArgsAndOpenPath(string path, Encoding encoding, FileStreamOptions options)
{
ValidateArgs(path, encoding);

if (options is null)
{
throw new ArgumentNullException(nameof(options));
}
if ((options.Access & FileAccess.Read) == 0)
{
throw new ArgumentException(nameof(options));
}

return new FileStream(path, options);
}

private static Stream ValidateArgsAndOpenPath(string path, Encoding encoding, int bufferSize)
{
ValidateArgs(path, encoding);
if (bufferSize <= 0)
throw new ArgumentOutOfRangeException(nameof(bufferSize));

return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultFileStreamBufferSize);
}

private static void ValidateArgs(string path, Encoding encoding)
{
if (path == null)
throw new ArgumentNullException(nameof(path));
if (encoding == null)
throw new ArgumentNullException(nameof(encoding));
if (path.Length == 0)
throw new ArgumentException();
}

public bool EndOfStream
{
get
{
ThrowIfDisposed();

if (_charPos < _charLen)
{
return false;
}

// This may block on pipes!
int numRead = ReadBuffer();
return numRead == 0;
}
}

}
}
8 changes: 0 additions & 8 deletions ExtSort/Models/Arguments/GeneratorArgument.cs

This file was deleted.

11 changes: 0 additions & 11 deletions ExtSort/Models/Arguments/SorterArgument.cs

This file was deleted.

32 changes: 32 additions & 0 deletions ExtSort/Models/Binders/EvaluatorBinder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using ExtSort.Services.Factories;

using System.CommandLine.Parsing;

namespace ExtSort.Models.Binders
{
internal record EvaluatorBinder()
{
public EvaluatorBinder(ParseResult parser) : this()
{
var args = ArgumentFactory.EvaluatorArguments.Value;

if (!int.TryParse(parser.GetValueForArgument(args[nameof(DiskLatencyMs)])?.ToString(), out var diskLatencyMs))
throw new InvalidCastException("The size of RAM available is in incorrect format.");
if (!int.TryParse(parser.GetValueForArgument(args[nameof(DiskRandomReadSpeedMbs)])?.ToString(), out var diskRandomReadSpeedMbs))
throw new InvalidCastException("The size of RAM available is in incorrect format.");

FileSizeMb = (int)parser.GetValueForArgument(args[nameof(FileSizeMb)]);
RamAvailableMb = (int)parser.GetValueForArgument(args[nameof(RamAvailableMb)]);
NumberOfFiles = (int)parser.GetValueForArgument(args[nameof(NumberOfFiles)]);

DiskLatencyMs = diskLatencyMs;
DiskRandomReadSpeedMbs = diskRandomReadSpeedMbs;
}

public int FileSizeMb { get; init; }
public int RamAvailableMb { get; init; }
public int NumberOfFiles { get; init; }
public int DiskLatencyMs { get; init; }
public int DiskRandomReadSpeedMbs { get; init; }
}
}
22 changes: 22 additions & 0 deletions ExtSort/Models/Binders/GeneratorBinder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using ExtSort.Services.Factories;
using System.CommandLine.Parsing;

namespace ExtSort.Models.Binders
{
internal record GeneratorBinder
{
public GeneratorBinder(ParseResult parser)
{
var args = ArgumentFactory.GeneratorArguments.Value;

if (!long.TryParse(parser.GetValueForArgument(args[nameof(TargetFileSizeKb)])?.ToString(), out var fileSizeKb))
throw new InvalidCastException("The length of the output file is in incorrect format.");

TargetFileSizeKb = fileSizeKb;
TargetFileName = (string)parser.GetValueForArgument(args[nameof(TargetFileName)]);
}

public string TargetFileName { get; init; }
public long TargetFileSizeKb { get; init; }
}
}
23 changes: 23 additions & 0 deletions ExtSort/Models/Binders/SorterBinder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using ExtSort.Code.Enums;
using ExtSort.Services.Factories;

using System.CommandLine.Parsing;

namespace ExtSort.Models.Binders
{
internal record SorterBinder
{
public SorterBinder(ParseResult parser)
{
var args = ArgumentFactory.SorterArguments.Value;

TargetFileName = (string)parser.GetValueForArgument(args[nameof(TargetFileName)]);
SourceFileName = (string)parser.GetValueForArgument(args[nameof(SourceFileName)]);
Mode = (SortMode)parser.GetValueForArgument(args[nameof(Mode)]);
}

public string TargetFileName { get; init; }
public string SourceFileName { get; init; }
public SortMode Mode { get; init; }
}
}
31 changes: 31 additions & 0 deletions ExtSort/Models/Settings/EvaluatorSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using ExtSort.Models.Binders;

using System.Text;

namespace ExtSort.Models.Settings
{
internal record EvaluatorSettings : EvaluatorBinder
{
public EvaluatorSettings(EvaluatorBinder settings) : base(settings)
{

}

public bool Validate(out StringBuilder errors)
{
errors = new StringBuilder();
if (NumberOfFiles < 1)
errors.AppendLine("The number of files must be equal or greater than 1");
if (RamAvailableMb <= 0)
errors.AppendLine("The RAM available must be greater than 0");
if (FileSizeMb <= 0)
errors.AppendLine("The file size must be greater than 0");
if (DiskLatencyMs < 0)
errors.AppendLine("The disk latency cannot be negative");
if (DiskRandomReadSpeedMbs <= 0)
errors.AppendLine("The disk random access speed must be greather than 0");

return errors.Length == 0;
}
}
}
6 changes: 5 additions & 1 deletion ExtSort/Models/Settings/FormatSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public record FormatSettings
public string EncodingName { get; init; } = "utf-8";
public bool UsePreamble { get; init; } = true;
public string ColumnSeparator { get; init; } = ".";
public char NewLineDelimiter { get; init; } = '\n';
public char? NewLineDelimiter { get; init; } = '\n';

public bool Validate(out StringBuilder errors)
{
Expand All @@ -16,6 +16,10 @@ public bool Validate(out StringBuilder errors)
errors.AppendLine("The encoding name is not specified");
if (string.IsNullOrEmpty(ColumnSeparator))
errors.AppendLine("The column separator string is not specified");
if (NewLineDelimiter == null)
errors.AppendLine("The new line delimiter character is not specified");
if (NewLineDelimiter == char.MinValue)
errors.AppendLine("The new line delimiter must differs from the NULL symbol");
if (!Encoding.GetEncodings().Any(arg => arg.Name == EncodingName))
errors.AppendLine($"The provided encoding {EncodingName} does not exist");

Expand Down
2 changes: 1 addition & 1 deletion ExtSort/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
},
"EvaluateDebugProfile": {
"commandName": "Project",
"commandLineArgs": "eval"
"commandLineArgs": "eval 1024 4096 64 100 10"
},
"HelpProfile": {
"commandName": "Project",
Expand Down
Loading

0 comments on commit 2695826

Please sign in to comment.