--- a/src/Compiler/Facilities/Hashing.fs
+++ b/src/Compiler/Facilities/Hashing.fs
@@ -1,6 +1,7 @@
namespace Internal.Utilities.Hashing
open System
+open System.Security.Cryptography
open System.Threading
@@ -43,19 +44,50 @@ module internal Md5StringHasher =
module internal Md5Hasher =
+#if NETSTANDARD2_0
let private md5 =
- new ThreadLocal<_>(fun () -> System.Security.Cryptography.MD5.Create())
+ new ThreadLocal<_>(fun () -> MD5.Create())
- let computeHash (bytes: byte array) =
- // md5.Value.ComputeHash(bytes) TODO: the threadlocal is not working in new VS extension
- ignore md5
- let md5 = System.Security.Cryptography.MD5.Create()
- md5.ComputeHash(bytes)
+ let computeHash (bytes: byte array) = md5.Value.ComputeHash(bytes)
+#else
+ let computeHash (bytes: byte array) = MD5.HashData(bytes)
+#endif
@@
let empty = Array.empty
@@
+ /// Computes the MD5 hash of a string directly into a caller-allocated 16-byte buffer,
+ /// avoiding the extra allocation of an intermediate hash-result array.
+ /// The UTF8 encoding buffer is rented from the shared ArrayPool to avoid allocating
+ /// a byte array the size of the input string on every call.
+ let hashStringInto (s: string) (destination: Span<byte>) =
+ let encoding = System.Text.Encoding.UTF8
+ let maxByteCount = encoding.GetMaxByteCount(s.Length)
+ let rented = System.Buffers.ArrayPool<byte>.Shared.Rent(maxByteCount)
+
+ try
+ let byteCount = encoding.GetBytes(s, 0, s.Length, rented, 0)
+#if NETSTANDARD2_0
+ let hash = md5.Value.ComputeHash(rented, 0, byteCount)
+ hash.CopyTo(destination)
+#else
+ let mutable bytesWritten = 0
+ MD5.TryHashData(ReadOnlySpan(rented, 0, byteCount), destination, &bytesWritten) |> ignore
+#endif
+ finally
+ System.Buffers.ArrayPool<byte>.Shared.Return(rented)
@@
- let hashString (s: string) =
- s |> System.Text.Encoding.UTF8.GetBytes |> computeHash
+ let hashString (s: string) =
+ let bytes = Array.zeroCreate<byte> 16
+ hashStringInto s (Span bytes)
+ bytes
@@
- let hashStringToString (s: string) =
- s |> System.Text.Encoding.UTF8.GetBytes |> computeHash
+ let hashStringToString (s: string) =
+ let bytes = Array.zeroCreate<byte> 16
+ hashStringInto s (Span bytes)
+ BitConverter.ToString(bytes)
The following staged changes are ready for review: