Skip to content

Commit

Permalink
Avoid boxing
Browse files Browse the repository at this point in the history
  • Loading branch information
sakno committed Mar 14, 2024
1 parent 946af08 commit 1b7bf85
Showing 1 changed file with 19 additions and 9 deletions.
28 changes: 19 additions & 9 deletions src/DotNext/IO/SharedReadOnlyMemoryStream.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
using System.Buffers;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace DotNext.IO;

using static Buffers.Memory;

internal sealed class SharedReadOnlyMemoryStream(ReadOnlySequence<byte> sequence) : ReadOnlyStream
{
private readonly AsyncLocal<SequencePosition> position = new();
// don't use BoxedValue due to limitations of AsyncLocal
private readonly AsyncLocal<StrongBox<SequencePosition>> position = new();

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private SequencePosition LocalPosition
{
get => position.Value?.Value ?? sequence.Start;
set => (position.Value ??= new()).Value = value;
}

private ReadOnlySequence<byte> GetRemainingSequence(out SequencePosition start)
=> sequence.Slice(start = position.Value);
=> sequence.Slice(start = LocalPosition);

public override bool CanSeek => true;

public override long Length => sequence.Length;

public override long Position
{
get => sequence.GetOffset(position.Value);
get => sequence.GetOffset(LocalPosition);
set
{
ArgumentOutOfRangeException.ThrowIfGreaterThan((ulong)value, (ulong)sequence.Length, nameof(value));

position.Value = sequence.GetPosition(value);
LocalPosition = sequence.GetPosition(value);
}
}

Expand All @@ -33,7 +43,7 @@ public override async Task CopyToAsync(Stream destination, int bufferSize, Cance
foreach (var segment in GetRemainingSequence(out _))
await destination.WriteAsync(segment, token).ConfigureAwait(false);

position.Value = sequence.End;
LocalPosition = sequence.End;
}

public override void CopyTo(Stream destination, int bufferSize)
Expand All @@ -43,15 +53,15 @@ public override void CopyTo(Stream destination, int bufferSize)
foreach (var segment in GetRemainingSequence(out _))
destination.Write(segment.Span);

position.Value = sequence.End;
LocalPosition = sequence.End;
}

public override void SetLength(long value) => throw new NotSupportedException();

public override int Read(Span<byte> buffer)
{
GetRemainingSequence(out var startPos).CopyTo(buffer, out var writtenCount);
position.Value = sequence.GetPosition(writtenCount, startPos);
LocalPosition = sequence.GetPosition(writtenCount, startPos);
return writtenCount;
}

Expand All @@ -60,7 +70,7 @@ public override long Seek(long offset, SeekOrigin origin)
var newPosition = origin switch
{
SeekOrigin.Begin => offset,
SeekOrigin.Current => sequence.GetOffset(position.Value) + offset,
SeekOrigin.Current => sequence.GetOffset(LocalPosition) + offset,
SeekOrigin.End => sequence.Length + offset,
_ => throw new ArgumentOutOfRangeException(nameof(origin))
};
Expand All @@ -70,7 +80,7 @@ public override long Seek(long offset, SeekOrigin origin)

ArgumentOutOfRangeException.ThrowIfGreaterThan(newPosition, sequence.Length, nameof(offset));

position.Value = sequence.GetPosition(newPosition);
LocalPosition = sequence.GetPosition(newPosition);
return newPosition;
}

Expand Down

0 comments on commit 1b7bf85

Please sign in to comment.