murmurhash-net
murmurhash-net copied to clipboard
Error on TryComputeHash
The generic HashAlgorithm.TryComputeHash(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten) implementation of this function gives an error on the FinalBlock call.
It would be nice to overload this method
I experienced the same problem today when I was reimplementing MurmurHash myself and was running tests that compared my implementation to this library's implementations as a reference.
- The root cause is (what I consider) a poor API design in .NET's
HashAlgorithmclass: when you subclassHashAlgorithmyou need to set the hash length; this can be done in two ways:- By either setting the
protected Int32 HashSizeValuefield in your constructor - or anywhere in your subclass (because the field is fully mutable and notreadonly). - Or by overriding the
public virtual Int32 HashSize { get; }property. - However, if you only override
HashSizeand never setHashSizeValuethen you'll get this error.
- By either setting the
- When
HashAlgorithmadded support forSpan<Byte>in the newvirtualmethodsTryComputeHashandTryHashFinal, the default implementations only check theprotected Int32 HashSizeValuefield and not the property. - ...but this
MurmurHashXXlibrary only overrides the properties, it never sets theHashSizeValuefield. - So the default implementations throw the
InvalidOperationException"The algorithm's implementation is incorrect." because it thinks the hash length is 0 bytes, instead of 4 or 16. - Subclassing
MurmurHash32andMurmurHash128isn't really a feasible option, but the good news is that you can use reflection to correctly set the field right-after you get an instance of the objects.
Like so:
private static readonly FieldInfo _hashAlgorithm_HashSizeValue_Field = typeof(HashAlgorithm).GetField( "HashSizeValue", BindingFlags.NonPublic | BindingFlags.Instance ) ?? throw new InvalidOperationException( "Couldn't find HashAlgorithm.HashSizeValue field." );
private static void FixHashSizeValueField( this HashAlgorithm hashAlgo )
{
_hashAlgorithm_HashSizeValue_Field.SetValue( obj: hashAlgo, value: hashAlgo.HashSize );
}