Implement Stream.Read(Span<byte>) overloads.
The default Stream implementation of this method has to rent an array so it can call the overload that accepts an array, and then copy the output over. This is because the array overload is required and the span overload was only added more recently. We can avoid the overhead of this by implementing the span overload and working with the destination span directly. Do so for all classes we have that derive from Stream, and redirect their array overload to the span overload for code reuse.
This commit is contained in:
committed by
Paul Chote
parent
d05b07a5b0
commit
b313f47660
@@ -80,18 +80,23 @@ namespace OpenRA.Primitives
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return Read(buffer.AsSpan(offset, count));
|
||||
}
|
||||
|
||||
public override int Read(Span<byte> buffer)
|
||||
{
|
||||
int bytesRead;
|
||||
|
||||
if (position >= Stream1.Length)
|
||||
bytesRead = Stream2.Read(buffer, offset, count);
|
||||
else if (count > Stream1.Length)
|
||||
bytesRead = Stream2.Read(buffer);
|
||||
else if (buffer.Length > Stream1.Length)
|
||||
{
|
||||
bytesRead = Stream1.Read(buffer, offset, (int)Stream1.Length);
|
||||
bytesRead += Stream2.Read(buffer, (int)Stream1.Length, count - (int)Stream1.Length);
|
||||
bytesRead = Stream1.Read(buffer[..(int)Stream1.Length]);
|
||||
bytesRead += Stream2.Read(buffer[(int)Stream1.Length..]);
|
||||
}
|
||||
else
|
||||
bytesRead = Stream1.Read(buffer, offset, count);
|
||||
bytesRead = Stream1.Read(buffer);
|
||||
|
||||
position += bytesRead;
|
||||
|
||||
@@ -108,6 +113,11 @@ namespace OpenRA.Primitives
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Write(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override bool CanRead => Stream1.CanRead && Stream2.CanRead;
|
||||
|
||||
public override bool CanSeek => Stream1.CanSeek && Stream2.CanSeek;
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace OpenRA.Primitives
|
||||
public sealed override void SetLength(long value) { throw new NotSupportedException(); }
|
||||
public sealed override void WriteByte(byte value) { throw new NotSupportedException(); }
|
||||
public sealed override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
|
||||
public override void Write(ReadOnlySpan<byte> buffer) { throw new NotSupportedException(); }
|
||||
public sealed override void Flush() { throw new NotSupportedException(); }
|
||||
|
||||
public sealed override int ReadByte()
|
||||
@@ -70,31 +71,36 @@ namespace OpenRA.Primitives
|
||||
|
||||
public sealed override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
var copied = 0;
|
||||
ConsumeData(buffer, offset, count, ref copied);
|
||||
return Read(buffer.AsSpan(offset, count));
|
||||
}
|
||||
|
||||
while (copied < count && !baseStreamEmpty)
|
||||
public override int Read(Span<byte> buffer)
|
||||
{
|
||||
var copied = 0;
|
||||
ConsumeData(buffer, ref copied);
|
||||
|
||||
while (copied < buffer.Length && !baseStreamEmpty)
|
||||
{
|
||||
baseStreamEmpty = BufferData(baseStream, data);
|
||||
ConsumeData(buffer, offset, count, ref copied);
|
||||
ConsumeData(buffer, ref copied);
|
||||
}
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads data into a buffer, which will be used to satisfy <see cref="ReadByte()"/> and
|
||||
/// <see cref="Read(byte[], int, int)"/> calls.
|
||||
/// Reads data into a buffer, which will be used to satisfy <see cref="ReadByte()"/>,
|
||||
/// <see cref="Read(byte[], int, int)"/> and <see cref="Read(Span{byte})"/> calls.
|
||||
/// </summary>
|
||||
/// <param name="baseStream">The source stream from which bytes should be read.</param>
|
||||
/// <param name="data">The queue where bytes should be enqueued. Do not dequeue from this buffer.</param>
|
||||
/// <returns>Return true if all data has been read; otherwise, false.</returns>
|
||||
protected abstract bool BufferData(Stream baseStream, Queue<byte> data);
|
||||
|
||||
void ConsumeData(byte[] buffer, int offset, int count, ref int copied)
|
||||
void ConsumeData(Span<byte> buffer, ref int copied)
|
||||
{
|
||||
while (copied < count && data.Count > 0)
|
||||
buffer[offset + copied++] = data.Dequeue();
|
||||
while (copied < buffer.Length && data.Count > 0)
|
||||
buffer[copied++] = data.Dequeue();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
|
||||
@@ -68,11 +68,16 @@ namespace OpenRA.Primitives
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return Read(buffer.AsSpan(offset, count));
|
||||
}
|
||||
|
||||
public override int Read(Span<byte> buffer)
|
||||
{
|
||||
var remaining = Length - Position;
|
||||
if (remaining <= 0)
|
||||
return 0;
|
||||
return BaseStream.Read(buffer, offset, (int)Math.Min(remaining, count));
|
||||
return BaseStream.Read(buffer[..(int)Math.Min(remaining, buffer.Length)]);
|
||||
}
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
@@ -84,9 +89,14 @@ namespace OpenRA.Primitives
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (Position + count >= Length)
|
||||
Write(buffer.AsSpan(offset, count));
|
||||
}
|
||||
|
||||
public override void Write(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
if (Position + buffer.Length >= Length)
|
||||
throw new IOException("Attempted to write past the end of the stream.");
|
||||
BaseStream.Write(buffer, offset, count);
|
||||
BaseStream.Write(buffer);
|
||||
}
|
||||
|
||||
public override void Flush() { BaseStream.Flush(); }
|
||||
|
||||
@@ -332,18 +332,16 @@ namespace OpenRA.Mods.Cnc.AudioLoaders
|
||||
}
|
||||
}
|
||||
|
||||
int Read(byte[] buffer, int offset, int count)
|
||||
int Read(Span<byte> buffer)
|
||||
{
|
||||
var bytesWritten = 0;
|
||||
var samplesLeft = Math.Min(count, buffer.Length - offset);
|
||||
while (samplesLeft > 0)
|
||||
while (buffer.Length > 0)
|
||||
{
|
||||
var len = FillBuffer(samplesLeft);
|
||||
var len = FillBuffer(buffer.Length);
|
||||
if (len == 0)
|
||||
break;
|
||||
Buffer.BlockCopy(this.buffer, 0, buffer, offset, len);
|
||||
samplesLeft -= len;
|
||||
offset += len;
|
||||
this.buffer.AsSpan(..len).CopyTo(buffer);
|
||||
buffer = buffer[len..];
|
||||
bytesWritten += len;
|
||||
}
|
||||
|
||||
@@ -372,13 +370,19 @@ namespace OpenRA.Mods.Cnc.AudioLoaders
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return format.Read(buffer, offset, count);
|
||||
return Read(buffer.AsSpan(offset, count));
|
||||
}
|
||||
|
||||
public override int Read(Span<byte> buffer)
|
||||
{
|
||||
return format.Read(buffer);
|
||||
}
|
||||
|
||||
public override void Flush() { throw new NotImplementedException(); }
|
||||
public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); }
|
||||
public override void SetLength(long value) { throw new NotImplementedException(); }
|
||||
public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); }
|
||||
public override void Write(ReadOnlySpan<byte> buffer) { throw new NotImplementedException(); }
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
|
||||
@@ -96,9 +96,14 @@ namespace OpenRA.Mods.Common.AudioLoaders
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return Read(buffer.AsSpan(offset, count));
|
||||
}
|
||||
|
||||
public override int Read(Span<byte> buffer)
|
||||
{
|
||||
// Adjust count so it is in 16-bit samples instead of bytes.
|
||||
count /= 2;
|
||||
var count = buffer.Length / 2;
|
||||
|
||||
// Make sure we don't have an odd count.
|
||||
count -= count % format.reader.Channels;
|
||||
@@ -112,8 +117,8 @@ namespace OpenRA.Mods.Common.AudioLoaders
|
||||
for (var i = 0; i < samples; i++)
|
||||
{
|
||||
var conversion = (short)(floatBuffer[i] * 32767);
|
||||
buffer[offset++] = (byte)(conversion & 255);
|
||||
buffer[offset++] = (byte)(conversion >> 8);
|
||||
buffer[i * 2 + 0] = (byte)(conversion & 255);
|
||||
buffer[i * 2 + 1] = (byte)(conversion >> 8);
|
||||
}
|
||||
|
||||
// Adjust count back to bytes.
|
||||
@@ -124,6 +129,7 @@ namespace OpenRA.Mods.Common.AudioLoaders
|
||||
public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); }
|
||||
public override void SetLength(long value) { throw new NotImplementedException(); }
|
||||
public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); }
|
||||
public override void Write(ReadOnlySpan<byte> buffer) { throw new NotImplementedException(); }
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user