Skip to content
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

Add NonCryptographicHashAlgorithm Clone methods #113087

Merged
merged 1 commit into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/libraries/System.IO.Hashing/ref/System.IO.Hashing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public sealed partial class Crc32 : System.IO.Hashing.NonCryptographicHashAlgori
{
public Crc32() : base (default(int)) { }
public override void Append(System.ReadOnlySpan<byte> source) { }
public System.IO.Hashing.Crc32 Clone() { throw null; }
[System.CLSCompliantAttribute(false)]
public uint GetCurrentHashAsUInt32() { throw null; }
protected override void GetCurrentHashCore(System.Span<byte> destination) { }
Expand All @@ -25,6 +26,7 @@ public override void Reset() { }
public sealed partial class Crc64 : System.IO.Hashing.NonCryptographicHashAlgorithm
{
public Crc64() : base (default(int)) { }
public System.IO.Hashing.Crc64 Clone() { throw null; }
public override void Append(System.ReadOnlySpan<byte> source) { }
[System.CLSCompliantAttribute(false)]
public ulong GetCurrentHashAsUInt64() { throw null; }
Expand Down Expand Up @@ -64,6 +66,7 @@ public sealed partial class XxHash128 : System.IO.Hashing.NonCryptographicHashAl
public XxHash128() : base (default(int)) { }
public XxHash128(long seed) : base (default(int)) { }
public override void Append(System.ReadOnlySpan<byte> source) { }
public System.IO.Hashing.XxHash128 Clone() { throw null; }
protected override void GetCurrentHashCore(System.Span<byte> destination) { }
public static byte[] Hash(byte[] source) { throw null; }
public static byte[] Hash(byte[] source, long seed) { throw null; }
Expand All @@ -77,6 +80,7 @@ public sealed partial class XxHash3 : System.IO.Hashing.NonCryptographicHashAlgo
public XxHash3() : base (default(int)) { }
public XxHash3(long seed) : base (default(int)) { }
public override void Append(System.ReadOnlySpan<byte> source) { }
public System.IO.Hashing.XxHash3 Clone() { throw null; }
[System.CLSCompliantAttribute(false)]
public ulong GetCurrentHashAsUInt64() { throw null; }
protected override void GetCurrentHashCore(System.Span<byte> destination) { }
Expand All @@ -94,6 +98,7 @@ public sealed partial class XxHash32 : System.IO.Hashing.NonCryptographicHashAlg
public XxHash32() : base (default(int)) { }
public XxHash32(int seed) : base (default(int)) { }
public override void Append(System.ReadOnlySpan<byte> source) { }
public System.IO.Hashing.XxHash32 Clone() { throw null; }
[System.CLSCompliantAttribute(false)]
public uint GetCurrentHashAsUInt32() { throw null; }
protected override void GetCurrentHashCore(System.Span<byte> destination) { }
Expand All @@ -111,6 +116,7 @@ public sealed partial class XxHash64 : System.IO.Hashing.NonCryptographicHashAlg
public XxHash64() : base (default(int)) { }
public XxHash64(long seed) : base (default(int)) { }
public override void Append(System.ReadOnlySpan<byte> source) { }
public System.IO.Hashing.XxHash64 Clone() { throw null; }
[System.CLSCompliantAttribute(false)]
public ulong GetCurrentHashAsUInt64() { throw null; }
protected override void GetCurrentHashCore(System.Span<byte> destination) { }
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.IO.Hashing/src/System/IO/Hashing/Crc32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ public Crc32()
{
}

/// <summary>Initializes a new instance of the <see cref="Crc32"/> class using the state from another instance.</summary>
private Crc32(uint crc) : base(Size)
{
_crc = crc;
}

/// <summary>Returns a clone of the current instance, with a copy of the current instance's internal state.</summary>
/// <returns>A new instance that will produce the same sequence of values as the current instance.</returns>
public Crc32 Clone() => new(_crc);

/// <summary>
/// Appends the contents of <paramref name="source"/> to the data already
/// processed for the current hash computation.
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.IO.Hashing/src/System/IO/Hashing/Crc64.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ public Crc64()
{
}

/// <summary>Initializes a new instance of the <see cref="Crc64"/> class using the state from another instance.</summary>
private Crc64(ulong crc) : base(Size)
{
_crc = crc;
}

/// <summary>Returns a clone of the current instance, with a copy of the current instance's internal state.</summary>
/// <returns>A new instance that will produce the same sequence of values as the current instance.</returns>
public Crc64 Clone() => new(_crc);

/// <summary>
/// Appends the contents of <paramref name="source"/> to the data already
/// processed for the current hash computation.
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHash128.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ public XxHash128(long seed) : base(HashLengthInBytes)
Initialize(ref _state, (ulong)seed);
}

/// <summary>Initializes a new instance of the <see cref="XxHash128"/> class using the state from another instance.</summary>
private XxHash128(State state) : base(HashLengthInBytes)
{
_state = state;
}

/// <summary>Returns a clone of the current instance, with a copy of the current instance's internal state.</summary>
/// <returns>A new instance that will produce the same sequence of values as the current instance.</returns>
public XxHash128 Clone() => new(_state);

/// <summary>Computes the XXH128 hash of the provided <paramref name="source"/> data.</summary>
/// <param name="source">The data to hash.</param>
/// <returns>The XXH128 128-bit hash code of the provided data.</returns>
Expand Down
10 changes: 10 additions & 0 deletions src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHash3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ public XxHash3(long seed) : base(HashLengthInBytes)
Initialize(ref _state, (ulong)seed);
}

/// <summary>Initializes a new instance of the <see cref="XxHash3"/> class using the state from another instance.</summary>
private XxHash3(State state) : base(HashLengthInBytes)
{
_state = state;
}

/// <summary>Returns a clone of the current instance, with a copy of the current instance's internal state.</summary>
/// <returns>A new instance that will produce the same sequence of values as the current instance.</returns>
public XxHash3 Clone() => new(_state);

/// <summary>Computes the XXH3 hash of the provided <paramref name="source"/> data.</summary>
/// <param name="source">The data to hash.</param>
/// <returns>The XXH3 64-bit hash code of the provided data.</returns>
Expand Down
17 changes: 17 additions & 0 deletions src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHash32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,23 @@ public XxHash32(int seed)
Reset();
}

/// <summary>Initializes a new instance of the <see cref="XxHash32"/> class using the state from another instance.</summary>
private XxHash32(uint seed, State state, byte[]? holdback, int length) :
base(HashSize)
{
_seed = seed;
_state = state;
if (((int)length & 0x0F) > 0)
{
_holdback = (byte[]?)holdback?.Clone();
}
_length = length;
}

/// <summary>Returns a clone of the current instance, with a copy of the current instance's internal state.</summary>
/// <returns>A new instance that will produce the same sequence of values as the current instance.</returns>
public XxHash32 Clone() => new(_seed, _state, _holdback, _length);

/// <summary>
/// Resets the hash computation to the initial state.
/// </summary>
Expand Down
17 changes: 17 additions & 0 deletions src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHash64.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,23 @@ public XxHash64(long seed)
Reset();
}

/// <summary>Initializes a new instance of the <see cref="XxHash64"/> class using the state from another instance.</summary>
private XxHash64(ulong seed, State state, byte[]? holdback, long length) :
base(HashSize)
{
_seed = seed;
_state = state;
if (((int)length & 0x1F) > 0)
{
_holdback = (byte[]?)holdback?.Clone();
}
_length = length;
}

/// <summary>Returns a clone of the current instance, with a copy of the current instance's internal state.</summary>
/// <returns>A new instance that will produce the same sequence of values as the current instance.</returns>
public XxHash64 Clone() => new(_seed, _state, _holdback, _length);

/// <summary>
/// Resets the hash computation to the initial state.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.IO.Hashing/tests/Crc32Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public static IEnumerable<object[]> TestCases
};

protected override NonCryptographicHashAlgorithm CreateInstance() => new Crc32();
protected override NonCryptographicHashAlgorithm Clone(NonCryptographicHashAlgorithm instance) => ((Crc32)instance).Clone();

protected override byte[] StaticOneShot(byte[] source) => Crc32.Hash(source);

Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.IO.Hashing/tests/Crc64Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public static IEnumerable<object[]> TestCases
};

protected override NonCryptographicHashAlgorithm CreateInstance() => new Crc64();
protected override NonCryptographicHashAlgorithm Clone(NonCryptographicHashAlgorithm instance) => ((Crc64)instance).Clone();

protected override byte[] StaticOneShot(byte[] source) => Crc64.Hash(source);

Expand Down
26 changes: 26 additions & 0 deletions src/libraries/System.IO.Hashing/tests/NonCryptoHashTestDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ protected NonCryptoHashTestDriver(byte[] emptyHash)
}

protected abstract NonCryptographicHashAlgorithm CreateInstance();
protected abstract NonCryptographicHashAlgorithm Clone(NonCryptographicHashAlgorithm instance);

protected abstract byte[] StaticOneShot(byte[] source);
protected abstract byte[] StaticOneShot(ReadOnlySpan<byte> source);
Expand Down Expand Up @@ -283,6 +284,31 @@ public void StaticVerifyTryOneShotSpanTooShortNoWrites()
}
}

[Fact]
public void Clone_ProducesSameSequence()
{
NonCryptographicHashAlgorithm hash = CreateInstance();

for (int outer = 0; outer < 4; outer++)
{
NonCryptographicHashAlgorithm clone = Clone(hash);
Assert.Equal(hash.HashLengthInBytes, clone.HashLengthInBytes);
Assert.Equal(hash.GetCurrentHash(), clone.GetCurrentHash());

Random r = new Random(42);
byte[] bytes = new byte[r.Next(1, 10)];

for (int inner = 0; inner < 4; inner++)
{
r.NextBytes(bytes);
hash.Append(bytes);
clone.Append(bytes);

Assert.Equal(hash.GetCurrentHash(), clone.GetCurrentHash());
}
}
}

private void VerifyEmptyResult(ReadOnlySpan<byte> result)
{
if (!result.SequenceEqual(_emptyHash))
Expand Down
25 changes: 25 additions & 0 deletions src/libraries/System.IO.Hashing/tests/XxHash128Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,31 @@ public void Hash_Streaming_Expected()
}
}

[Fact]
public void Clone_ProducesSameSequence()
{
XxHash128 hash = new(42);

for (int outer = 0; outer < 4; outer++)
{
XxHash128 clone = hash.Clone();
Assert.Equal(hash.HashLengthInBytes, clone.HashLengthInBytes);
Assert.Equal(hash.GetCurrentHash(), clone.GetCurrentHash());

Random r = new Random(42);
byte[] bytes = new byte[r.Next(1, 10)];

for (int inner = 0; inner < 4; inner++)
{
r.NextBytes(bytes);
hash.Append(bytes);
clone.Append(bytes);

Assert.Equal(hash.GetCurrentHash(), clone.GetCurrentHash());
}
}
}

private static Hash128 ReadHashBigEndian(ReadOnlySpan<byte> span)
{
var high = BinaryPrimitives.ReadUInt64BigEndian(span);
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.IO.Hashing/tests/XxHash32Tests.007.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ public static IEnumerable<object[]> LargeTestCases
};

protected override NonCryptographicHashAlgorithm CreateInstance() => new XxHash32(Seed);
protected override NonCryptographicHashAlgorithm Clone(NonCryptographicHashAlgorithm instance) => ((XxHash32)instance).Clone();

protected override byte[] StaticOneShot(byte[] source) => XxHash32.Hash(source, Seed);

Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.IO.Hashing/tests/XxHash32Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ public static IEnumerable<object[]> LargeTestCases
};

protected override NonCryptographicHashAlgorithm CreateInstance() => new XxHash32();
protected override NonCryptographicHashAlgorithm Clone(NonCryptographicHashAlgorithm instance) => ((XxHash32)instance).Clone();

protected override byte[] StaticOneShot(byte[] source) => XxHash32.Hash(source);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ public static IEnumerable<object[]> LargeTestCases
};

protected override NonCryptographicHashAlgorithm CreateInstance() => new XxHash32(Seed);
protected override NonCryptographicHashAlgorithm Clone(NonCryptographicHashAlgorithm instance) => ((XxHash32)instance).Clone();

protected override byte[] StaticOneShot(byte[] source) => XxHash32.Hash(source, Seed);

Expand Down
25 changes: 25 additions & 0 deletions src/libraries/System.IO.Hashing/tests/XxHash3Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,31 @@ public void Hash_Streaming_Expected()
}
}

[Fact]
public void Clone_ProducesSameSequence()
{
XxHash3 hash = new(42);

for (int outer = 0; outer < 4; outer++)
{
XxHash3 clone = hash.Clone();
Assert.Equal(hash.HashLengthInBytes, clone.HashLengthInBytes);
Assert.Equal(hash.GetCurrentHash(), clone.GetCurrentHash());

Random r = new Random(42);
byte[] bytes = new byte[r.Next(1, 10)];

for (int inner = 0; inner < 4; inner++)
{
r.NextBytes(bytes);
hash.Append(bytes);
clone.Append(bytes);

Assert.Equal(hash.GetCurrentHash(), clone.GetCurrentHash());
}
}
}

private static IEnumerable<(ulong Hash, long Seed, string Ascii)> TestCases()
{
yield return (Hash: 0x2d06800538d394c2UL, Seed: 0x0000000000000000L, Ascii: "");
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.IO.Hashing/tests/XxHash64Tests.007.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public static IEnumerable<object[]> TestCases
};

protected override NonCryptographicHashAlgorithm CreateInstance() => new XxHash64(Seed);
protected override NonCryptographicHashAlgorithm Clone(NonCryptographicHashAlgorithm instance) => ((XxHash64)instance).Clone();

protected override byte[] StaticOneShot(byte[] source) => XxHash64.Hash(source, Seed);

Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.IO.Hashing/tests/XxHash64Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ public static IEnumerable<object[]> LargeTestCases
};

protected override NonCryptographicHashAlgorithm CreateInstance() => new XxHash64();
protected override NonCryptographicHashAlgorithm Clone(NonCryptographicHashAlgorithm instance) => ((XxHash64)instance).Clone();

protected override byte[] StaticOneShot(byte[] source) => XxHash64.Hash(source);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ public static IEnumerable<object[]> LargeTestCases
};

protected override NonCryptographicHashAlgorithm CreateInstance() => new XxHash64(Seed);
protected override NonCryptographicHashAlgorithm Clone(NonCryptographicHashAlgorithm instance) => ((XxHash64)instance).Clone();

protected override byte[] StaticOneShot(byte[] source) => XxHash64.Hash(source, Seed);

Expand Down
Loading