/// <summary> /// Reads a <see cref="IBufferReader{T}"/> to completion, writing to a <see cref="IBufferWriter{T}"/> /// </summary> /// <typeparam name="T">The type of element</typeparam> /// <param name="reader">The reader to read from</param> /// <param name="writer">The writer to write to</param> public static void CopyTo <T>(this IBufferReader <T> reader, IBufferWriter <T> writer) { while (reader.CanRead) { var InBuffer = reader.GetSpan(0); if (InBuffer.IsEmpty) { break; } var OutBuffer = writer.GetSpan(InBuffer.Length); InBuffer.CopyTo(OutBuffer); writer.Advance(InBuffer.Length); reader.Advance(InBuffer.Length); } }
int Read(Span <char> buffer) { //**************************************** var CharsWritten = 0; //**************************************** if (buffer.IsEmpty) { return(0); } // Empty the buffer if there's anything in it if (_BufferLength > 0) { var WriteLength = Math.Min(_BufferLength, buffer.Length); _Buffer.AsSpan(_BufferIndex, WriteLength).CopyTo(buffer); buffer = buffer.Slice(WriteLength); CharsWritten += WriteLength; _BufferIndex += WriteLength; _BufferLength -= WriteLength; if (buffer.IsEmpty) { return(CharsWritten); } } if (_CheckPreamble) { CheckPreamble(); } if (_DetectEncoding) { DetectEncoding(); } ReadOnlySpan <byte> InBuffer; var OutBuffer = _Buffer.AsSpan(0, _Buffer.Length); bool IsCompleted; // Keep trying to read until we fill the buffer, or the source reader runs out do { InBuffer = _Reader.GetSpan(0); // Decode the bytes into our char buffer _Decoder.Convert( InBuffer, OutBuffer, InBuffer.IsEmpty, out var BytesRead, out var WrittenChars, out IsCompleted ); var ReadLength = Math.Min(WrittenChars, buffer.Length); OutBuffer.Slice(0, ReadLength).CopyTo(buffer); buffer = buffer.Slice(ReadLength); CharsWritten += ReadLength; _Position += BytesRead; _Reader.Advance(BytesRead); if (buffer.IsEmpty) { // Buffer is filled. Save any data left over for the next read operation _BufferIndex = ReadLength; _BufferLength = WrittenChars - ReadLength; return(CharsWritten); } // Loop while there are more bytes unread, or there are no bytes left but there's still data to flush }while (!InBuffer.IsEmpty || !IsCompleted); _BufferLength = 0; return(CharsWritten); }
public static void CopyTo(this IBufferReader <byte> source, Stream target) => source.CopyTo(target, 81920); // Same buffer size as Stream.CopyTo /// <summary> /// Synchronously reads the bytes from the current <see cref="IBufferReader{Byte}"/> and writes them to a Stream /// </summary> /// <param name="source">The current buffer reader to read from</param> /// <param name="target">The stream to write to</param> /// <param name="blockSize">The size of the blocks to read and write</param> public static void CopyTo(this IBufferReader <byte> source, Stream target, int blockSize) { if (blockSize < 0) { throw new ArgumentOutOfRangeException(nameof(blockSize)); } #if NETSTANDARD2_0 byte[]? InBuffer = null; try { for (; ;) { var Buffer = source.GetMemory(blockSize); if (Buffer.IsEmpty) { break; } if (MemoryMarshal.TryGetArray(Buffer, out var Segment)) { // Have the stream write directly from the source buffer target.Write(Segment.Array, Segment.Offset, Segment.Count); source.Advance(Segment.Count); } else { // Not a buffer we can pass to Stream.Write, so we have to copy if (InBuffer == null) { InBuffer = ArrayPool <byte> .Shared.Rent(Buffer.Length); } var Length = Math.Min(Buffer.Length, InBuffer.Length); Buffer.Slice(0, Length).CopyTo(InBuffer); target.Write(InBuffer, 0, Length); source.Advance(Length); } } } finally { if (InBuffer != null) { ArrayPool <byte> .Shared.Return(InBuffer); } } #else for (; ;) { var Buffer = source.GetSpan(blockSize); if (Buffer.IsEmpty) { break; } target.Write(Buffer); source.Advance(Buffer.Length); } #endif }