using System; using System.Buffers; using System.Collections.Generic; namespace Microsoft.AspNetCore.SignalR.Internal { public sealed class MemoryBufferWriter : IBufferWriter { private readonly int _segmentSize; internal List> Segments { get; } internal int Position { get; private set; } public MemoryBufferWriter(int segmentSize = 2048) { _segmentSize = segmentSize; Segments = new List>(); } public Memory CurrentSegment => Segments.Count > 0 ? Segments[Segments.Count - 1] : null; public void Advance(int count) { Position += count; } public Memory GetMemory(int sizeHint = 0) { // TODO: Use sizeHint if (Segments.Count == 0 || Position == _segmentSize) { // TODO: Rent memory from a pool Segments.Add(new Memory(new byte[_segmentSize])); Position = 0; } return CurrentSegment.Slice(Position, CurrentSegment.Length - Position); } public Span GetSpan(int sizeHint = 0) { return GetMemory(sizeHint).Span; } public byte[] ToArray() { if (Segments.Count == 0) { return Array.Empty(); } var totalLength = (Segments.Count - 1) * _segmentSize; totalLength += Position; var result = new byte[totalLength]; var totalWritten = 0; // Copy full segments for (int i = 0; i < Segments.Count - 1; i++) { Segments[i].CopyTo(result.AsMemory(totalWritten, _segmentSize)); totalWritten += _segmentSize; } // Copy current incomplete segment CurrentSegment.Slice(0, Position).CopyTo(result.AsMemory(totalWritten, Position)); return result; } } }