Skip to content

Commit

Permalink
Reduce some allocations during load phase
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma committed Aug 10, 2023
1 parent 3016ad9 commit b85464e
Show file tree
Hide file tree
Showing 2 changed files with 199 additions and 6 deletions.
189 changes: 189 additions & 0 deletions src/Test262Harness/MemoryReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
namespace System.IO;

internal sealed class MemoryReader : TextReader
{
private readonly ReadOnlyMemory<char> _s;
private int _pos;
private int _length;
private bool _disposed;

public MemoryReader(ReadOnlyMemory<char> s)
{
_s = s;
_length = s.Length;
}

public override void Close()
{
Dispose(true);
}

protected override void Dispose(bool disposing)
{
_disposed = true;
_pos = 0;
_length = 0;
base.Dispose(disposing);
}

public override int Peek()
{
if (_disposed)
{
throw new ObjectDisposedException(null);
}
if (_pos == _length)
{
return -1;
}

return _s.Span[_pos];
}

// Reads the next character from the underlying string. The returned value
// is -1 if no further characters are available.
//
public override int Read()
{
if (_disposed)
{
throw new ObjectDisposedException(null);
}
if (_pos == _length)
{
return -1;
}

return _s.Span[_pos++];
}

public override int Read(char[] buffer, int index, int count)
{
int n = _length - _pos;
if (n > 0)
{
if (n > count)
{
n = count;
}

_s.Span.Slice(_pos, n).CopyTo(buffer.AsSpan(index));
_pos += n;
}
return n;
}

#if NET6_0_OR_GREATER
public override int Read(Span<char> buffer)
{
if (_disposed)
{
throw new ObjectDisposedException(null);
}

int n = _length - _pos;
if (n > 0)
{
if (n > buffer.Length)
{
n = buffer.Length;
}

_s.Span.Slice(_pos, n).CopyTo(buffer);
_pos += n;
}

return n;
}

public override int ReadBlock(Span<char> buffer) => Read(buffer);
#endif

public override string ReadToEnd()
{
if (_disposed)
{
throw new ObjectDisposedException(null);
}

ReadOnlySpan<char> s;
if (_pos == 0)
{
s = _s.Span;
}
else
{
s = _s.Span.Slice(_pos, _length - _pos);
}

_pos = _length;
return s.ToString();
}

public override string? ReadLine()
{
if (_disposed)
{
throw new ObjectDisposedException(null);
}

var span = _s.Span;
int i = _pos;
while (i < _length)
{
char ch = span[i];
if (ch == '\r' || ch == '\n')
{
var result = span.Slice(_pos, i - _pos);
_pos = i + 1;
if (ch == '\r' && _pos < _length && span[_pos] == '\n')
{
_pos++;
}

return result.ToString();
}

i++;
}

if (i > _pos)
{
var result = span.Slice(_pos, i - _pos);
_pos = i;
return result.ToString();
}

return null;
}

public override Task<string?> ReadLineAsync()
{
return Task.FromResult(ReadLine());
}

public override Task<string> ReadToEndAsync()
{
return Task.FromResult(ReadToEnd());
}

public override Task<int> ReadBlockAsync(char[] buffer, int index, int count)
{
return Task.FromResult(ReadBlock(buffer, index, count));
}

#if NET6_0_OR_GREATER
public override ValueTask<int> ReadBlockAsync(Memory<char> buffer, CancellationToken cancellationToken = default) =>
cancellationToken.IsCancellationRequested ? ValueTask.FromCanceled<int>(cancellationToken) : new ValueTask<int>(ReadBlock(buffer.Span));
#endif

public override Task<int> ReadAsync(char[] buffer, int index, int count)
{
return Task.FromResult(Read(buffer, index, count));
}

#if NET6_0_OR_GREATER
public override ValueTask<int> ReadAsync(Memory<char> buffer, CancellationToken cancellationToken = default) =>
cancellationToken.IsCancellationRequested ? ValueTask.FromCanceled<int>(cancellationToken) : new ValueTask<int>(Read(buffer.Span));
#endif
}
16 changes: 10 additions & 6 deletions src/Test262Harness/Test262File.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public sealed class Test262File : IEquatable<Test262File>
private const string YamlSectionStartMarker = "/*---";
private const string YamlSectionEndMarker = "---*/";

private static readonly YamlScalarNode _phaseNode = new("phase");
private static readonly YamlScalarNode _typeNode = new("type");
private static readonly string _useStrictWithNewLine = "\"use strict\";" + Environment.NewLine;

private string[] _features = Array.Empty<string>();
private string[] _flags = Array.Empty<string>();
private string[] _includes = Array.Empty<string>();
Expand Down Expand Up @@ -144,8 +148,8 @@ public static IEnumerable<Test262File> FromStream(Stream stream, string fileName
throw new ArgumentException($"Test case {fileName} is invalid, cannot find YAML section end.");
}

var yaml = contents.Substring(yamlStartIndex + YamlSectionStartMarker.Length, yamlEndIndex - YamlSectionEndMarker.Length - yamlStartIndex);
if (string.IsNullOrWhiteSpace(yaml))
var yaml = contents.AsMemory(yamlStartIndex + YamlSectionStartMarker.Length, yamlEndIndex - YamlSectionEndMarker.Length - yamlStartIndex);
if (yaml.IsEmpty)
{
throw new ArgumentException($"Test case {fileName} is invalid, cannot find YAML section.");
}
Expand All @@ -154,7 +158,7 @@ public static IEnumerable<Test262File> FromStream(Stream stream, string fileName
try
{
var yamlStream = new YamlStream();
yamlStream.Load(new StringReader(yaml));
yamlStream.Load(new MemoryReader(yaml));
document = yamlStream.Documents[0];
}
catch (Exception ex)
Expand Down Expand Up @@ -194,8 +198,8 @@ public static IEnumerable<Test262File> FromStream(Stream stream, string fileName
break;
case "negative":
var source = (YamlMappingNode) node.Value;
Enum.TryParse<TestingPhase>(source["phase"].ToString(), ignoreCase: true, out var phase);
Enum.TryParse<ExpectedErrorType>(source["type"].ToString(), ignoreCase: true, out var expectedErrorType);
Enum.TryParse<TestingPhase>(source[_phaseNode].ToString(), ignoreCase: true, out var phase);
Enum.TryParse<ExpectedErrorType>(source[_typeNode].ToString(), ignoreCase: true, out var expectedErrorType);

test.NegativeTestCase = new NegativeTestCase(phase, expectedErrorType);
break;
Expand Down Expand Up @@ -256,7 +260,7 @@ public Test262File AsStrict()

var clone = (Test262File) this.MemberwiseClone();
clone.Strict = true;
clone.Program = "\"use strict\";" + Environment.NewLine + Program;
clone.Program = _useStrictWithNewLine + Program;
return clone;
}

Expand Down

0 comments on commit b85464e

Please sign in to comment.