ssg / SimpleBase

.NET library for encoding/decoding Base16, Base32, Base58 and Base85.
Apache License 2.0
147 stars 21 forks source link

Add TryEncode/Decode methods #12

Closed devhawk closed 4 years ago

devhawk commented 5 years ago

Can you add non-allocating TryEncode/Decode methods that take a Span buffer to write into + an out int param indicated the number of bytes written. Essentially, have a signature similar to HashAlgorithm.TryComputeHash.

Would also be good to expose GetByteCount methods , similar to Encoding.GetByteCount.

ssg commented 5 years ago

@devhawk Thanks for the suggestion. Encode returns a string, what do you propose with an output Span, a Span<byte> or a Span<char>? I wonder about the actual uses cases.

devhawk commented 5 years ago

I would propose the signature bool TryEncode(ReadOnlySpan<byte> input, Span<char> output, out int bytesWritten)

devhawk commented 5 years ago

I want to write something like this, but for base58 encoding

public static bool TryInteropMethodHash(string methodName, out uint value)
{
    // Base58.Bitcoin.GetDecodeByteCount 
    Span<byte> asciiMethodName = stackalloc byte[(Encoding.ASCII.GetByteCount(methodName))];

    // I'm more of a fan of the Try* pattern here, with bytes written as an out param, but you get the idea
    var getBytesWritten = Encoding.ASCII.GetBytes(methodName, asciiMethodName);
    Debug.Assert(getBytesWritten == asciiMethodName.Length);

    // SHA256 hash is always the same size, so no need for a GetByteCount equivalent
    Span<byte> hashBuffer = stackalloc byte[Hash256Size];

    // This is the Try* pattern I like
    if (_sha256.Value.TryComputeHash(asciiMethodName, hashBuffer, out var hashBytesWritten))
    {
        Debug.Assert(hashBytesWritten == hashBuffer.Length);
        value = BitConverter.ToUInt32(hashBuffer.Slice(0, sizeof(uint)));
        return true;
    }

    value = default;
    return false;
}
ssg commented 5 years ago

I think GetByteCount for Base58.Decode would require the full decoding to be performed, so you'd essentially be doing twice the decoding which might be undesirable for a slow encoding like Base58.

Would it be okay to get something like GetSafeByteCount() (which can be couple of bytes more than the actual size) and rely on "hashBytesWritten" to process the actual size later? It might be a quite complicated interface but much faster.

devhawk commented 5 years ago

Yes, GetSafeByteCount would be fine as long as the actual bytes written count is returned by TryDecode

ssg commented 4 years ago

I added these to 3.0.0 release.