-
-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Proposal] Support ReadOnlySequence as input #61
Comments
Thanks for the proposal. I like the idea, but have to think about it a bit more, as the same / similar could apply to the "output". |
@ycrumeyrolle for your proposal what do you suggest for the "output"-side? If it tends to have overloads for pipelines, I'll rather push this to the consumer of this packages, as he knows where to read / write the data. If well find a good solution for the output side, then your proposal would be nice to have. |
Basically I would expect the same usage than the current implementation, I mean a Span as output. I was thinking something like this: public static OperationStatus Decode(in ReadOnlySequence<byte> base64Url, Span<byte> data, out int bytesConsumed, out int bytesWritten)
{
SequencePosition position = default;
Span<byte> span = data;
base64Url.TryGet(ref position, out ReadOnlyMemory<byte> previousSegment, advance: true);
int totalConsumed = 0;
int totalWritten = 0;
OperationStatus status;
while (base64Url.TryGet(ref position, out ReadOnlyMemory<byte> segment, advance: true))
{
status = _base64.Decode(previousSegment.Span, span, out bytesConsumed, out bytesWritten, isFinalBlock: false);
totalConsumed += bytesConsumed;
totalWritten += bytesWritten;
if (status != OperationStatus.NeedMoreData)
{
return status;
}
span = data.Slice(totalWritten);
previousSegment = segment;
}
status = _base64.Decode(previousSegment.Span, span, out bytesConsumed, out bytesWritten, isFinalBlock: true);
bytesConsumed += totalConsumed;
bytesWritten += totalWritten;
return status;
} |
How do you know how much space to allocate for |
You can assume the Otherwise, you may have to use a |
Ah, yes that obvious for In your example what is https://github.com/dotnet/corefx/issues/34761 shows an example where
So this would result in this API: using System;
using System.Buffers;
namespace gfoidl.Base64
{
public interface IBase64
{
int GetEncodedLength(int sourceLength);
int GetMaxDecodedLength(int encodedLength);
int GetDecodedLength(ReadOnlySpan<byte> encoded);
int GetDecodedLength(ReadOnlySpan<char> encoded);
OperationStatus Encode(ReadOnlySpan<byte> data, Span<byte> encoded, out int consumed, out int written, bool isFinalBlock = true);
OperationStatus Encode(ReadOnlySpan<byte> data, Span<char> encoded, out int consumed, out int written, bool isFinalBlock = true);
+ OperationStatus Encode(ReadOnlySequence<byte> data, IBufferWriter<byte> encoded, out long consumed, out long written);
+ OperationStatus Encode(ReadOnlySequence<byte> data, IBufferWriter<char> encoded, out long consumed, out long written);
OperationStatus Decode(ReadOnlySpan<byte> encoded, Span<byte> data, out int consumed, out int written, bool isFinalBlock = true);
OperationStatus Decode(ReadOnlySpan<char> encoded, Span<byte> data, out int consumed, out int written, bool isFinalBlock = true);
+ OperationStatus Decode(ReadOnlySequence<byte> encoded, IBufferWriter<byte> data, out long consumed, out long written);
+ OperationStatus Decode(ReadOnlySequence<char> encoded, IBufferWriter<byte> data, out long consumed, out long written);
string Encode(ReadOnlySpan<byte> data);
byte[] Decode(ReadOnlySpan<char> encoded);
}
} Note that Are the |
Should you put this on the interface or simply as en extension method ? I do not see any use case of If you use a You can simply propose another extension method that internally wrap a |
Oh... I was faced to a major problem I did not expect... Do you think it is possible to evolve the current implementation that integrate the remaining of a previous decoding, decode the remaining + the first bytes, then decode the rest of the span? public static OperationStatus Decode(ReadOnlySpan<byte> span, ReadOnlySpan<byte> remaining, Span<byte> data, out int bytesConsumed, out int bytesWritten)
{
if (!remaining.IsEmpty)
{
var offset = DecodeRemaining(remaining, span, data);
span = span.Slice(offset);
}
// continue decoding
} And of course without perf impact? :) |
Hm, extension methods seem to be the better way.
I think it's possible to do this (with slicing and second call to decode -- or like that). |
FYI: it's not forgotten, just no time for this at the moment. |
My last comment still applies 😉 Now I'd like to wait for the API review of https://github.com/dotnet/corefx/issues/41166, so these APIs here should be aligned to the API in corefx. One point I like there, is that |
From the motivation for this issue (The main use case I see is in AspNetCore by getting the data from the public static class ReadOnlySequenceExtensions
{
public static long Encode(this Base64? encoder, in ReadOnlySequence<byte> data, IBufferWriter<byte>? base64Writer);
public static bool TryDecode(this Base64? encoder, in ReadOnlySequence<byte> base64, IBufferWriter<byte>? dataWriter, out long consumed);
} Notes:
The span-bases overloads are left out at this step, but these can be added later if there is some demand for it. |
Ahh, I changed my mind again 😉 So the API is public static void Encode(this Base64? encoder, in ReadOnlySequence<byte> data, IBufferWriter<byte>? writer, out long consumed, out long written);
public static bool TryDecode(this Base64? encoder, in ReadOnlySequence<byte> base64, IBufferWriter<byte>? writer, out long consumed, out long written); |
* API defined As extension-method per #61 (comment) * Tests * Implementation * ReadMe and demo updated * Demo for ASP.NET Core BodyWriter * Added comment for hacky example [skip ci] * Added benchmark * Update source/gfoidl.Base64/ThrowHelper.cs Co-Authored-By: Yann Crumeyrolle <ycrumeyrolle@free.fr> * Whitespace * xml doc comments
The
Encode
/Decode
operations support aReadOnlySpan<byte>
as data input.It would be interesting to also support a
ReadOnlySequence<byte>
as data input for chunked data blocks.The text was updated successfully, but these errors were encountered: