using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Siia.Model.Infrastructure; using Siia.RedisCache; using Siia.Utility; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace Siia.Service.Message { class MessageQueueWorker { private readonly Task _task; private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private readonly EventWaitHandle _readyToStart = new EventWaitHandle(false, EventResetMode.AutoReset); private readonly ConcurrentQueue<MessageQueueRequest> _messagesQueue = new ConcurrentQueue<MessageQueueRequest>(); private readonly ILogger<MessageQueueWorker> _logger; private readonly IRedisService _redisService; public MessageQueueWorker(IServiceProvider serviceProvider) { _redisService = serviceProvider.GetService<IRedisService>(); this._logger = serviceProvider.GetService<ILogger<MessageQueueWorker>>(); this._task = Task.Factory.StartNew(async () => { this._readyToStart.WaitOne(); while (!this._cancellationTokenSource.IsCancellationRequested) { if (this._messagesQueue.TryDequeue(out var message)) { switch (message.MessageQueueType) { case MessageQueueType.SheepRecord: message.Waiter.TrySetResult(await CheckSheepRecord(message.Body as MQ_CreateSheepRecordQueueRequest)); break; default: break; } } else Thread.Sleep(1); } }, this._cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); } public void TryProcessMessage(MessageQueueRequest message) => this._messagesQueue.Enqueue(message); public void Start() => this._readyToStart.Set(); public void Shutdown() { this._cancellationTokenSource.Cancel(); _task?.Wait(); this._readyToStart.Dispose(); this._cancellationTokenSource.Dispose(); } public async Task<ActionResponse> CheckSheepRecord(MQ_CreateSheepRecordQueueRequest request) { var existTagList = new List<string>(); foreach (var item in request.EarTagCodeList) { var codeNum = await _redisService.HashIncrementAsync("EarCode_Record_Item", item, async () => { await Task.CompletedTask; return 0; }, 1); if (codeNum > 1) existTagList.Add(item); } await _redisService.KeyExpireAsync("EarCode_Record_Item", DateTime.Now.AddHours(1)); if (existTagList.Any()) return ActionResponse.Succeed(new { ReturnCode = -1, Message = "耳标已建档", Data = existTagList }); return ActionResponse.Fail(-1,""); } } public class MessageQueueFunc { private readonly int _workerCount = 2; private readonly List<MessageQueueWorker> _workerList = new List<MessageQueueWorker>(); public MessageQueueFunc(IServiceProvider serviceProvider) { for (var i = 0; i < _workerCount; i++) { var worker = new MessageQueueWorker(serviceProvider); this._workerList.Add(worker); } } public void Start() { for (int i = 0; i < this._workerCount; i++) { this._workerList[i].Start(); } } public void Shutdown() { for (int i = 0; i < this._workerCount; i++) { this._workerList[i].Shutdown(); } } public async Task<ActionResponse> MessageQueue(MessageQueueRequest request) { var index = (int)(Farmhash.Hash32(request.RoutingKey) % this._workerCount); var worker = this._workerList[index]; var body = request; worker.TryProcessMessage(body); return await body.Waiter.Task; } } public class MessageQueueRequest { public MessageQueueRequest() { Waiter = new TaskCompletionSource<ActionResponse>(); } public MessageQueueType MessageQueueType { get; set; } public string RoutingKey { get; set; } public object Body { get; set; } public TaskCompletionSource<ActionResponse> Waiter { get; set; } } public enum MessageQueueType : byte { /// <summary> /// 羊只建档 /// </summary> SheepRecord = 1 } public class MQ_CreateSheepRecordQueueRequest { public List<string> EarTagCodeList { get; set; } } }
app.ApplicationServices.GetService<MessageQueueFunc>().Start();
services.AddSingleton<MessageQueueFunc>();
调用:
//var checkResult = await _messageQueueFunc.MessageQueue(new MessageQueueRequest //{ // MessageQueueType = MessageQueueType.SheepRecord, // RoutingKey = "AddSheepRecord", // Body = new MQ_CreateSheepRecordQueueRequest { EarTagCodeList = tagList } //}); //if (checkResult.IsSuccess) return checkResult;
Farmhash:
using System; using System.Runtime.CompilerServices; namespace Siia.Utility { /// <summary> /// Class that can calculate 32bit and 64bit hashes using /// <see href="https://github.com/google/farmhash"> /// Google's farmhash /// </see> /// algorithm /// </summary> public static class Farmhash { private struct uint128_t { public ulong first, second; public uint128_t(ulong first, ulong second) { this.first = first; this.second = second; } } // Some primes between 2^63 and 2^64 for various uses. private const ulong k0 = 0xc3a5c85c97cb3127U; private const ulong k1 = 0xb492b66fbe98f273U; private const ulong k2 = 0x9ae16a3b2f90404fU; // Magic numbers for 32-bit hashing. Copied from Murmur3. private const uint c1 = 0xcc9e2d51; private const uint c2 = 0x1b873593; // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L209-L212 private static uint Rotate32(uint val, int shift) => shift == 0 ? val : (val >> shift) | (val << (32 - shift)); // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L214-L217 private static ulong Rotate64(ulong val, int shift) => shift == 0 ? val : (val >> shift) | (val << (64 - shift)); private static uint Rotate(uint val, int shift) => Rotate32(val, shift); // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L192-L196 private static unsafe ulong Fetch64(byte* p) => *(ulong*)p; // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L198-L202 private static unsafe uint Fetch32(byte* p) => *(uint*)p; private static unsafe uint Fetch(byte* p) => Fetch32(p); // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L360-L369 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint fmix(uint h) { h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; h *= 0xc2b2ae35; h ^= h >> 16; return h; } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L1042-L1051 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe uint Hash32Len0to4(byte* s, uint len, uint seed = 0) { uint b = seed; uint c = 9; for (int i = 0; i < len; i++) { b = b * c1 + s[i]; c ^= b; } return fmix(Mur(b, Mur(len, c))); } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L371-L379 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint Mur(uint a, uint h) { // Helper from Murmur3 for combining two 32-bit values. a *= c1; a = Rotate32(a, 17); a *= c2; h ^= a; h = Rotate32(h, 19); return h * 5 + 0xe6546b64; } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L1025-L1040 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe uint Hash32Len13to24(byte* s, uint len, uint seed = 0) { uint a = Fetch(s - 4 + (len >> 1)); uint b = Fetch(s + 4); uint c = Fetch(s + len - 8); uint d = Fetch(s + (len >> 1)); uint e = Fetch(s); uint f = Fetch(s + len - 4); uint h = d * c1 + len + seed; a = Rotate(a, 12) + f; h = Mur(c, h) + a; a = Rotate(a, 3) + c; h = Mur(e, h) + a; a = Rotate(a + f, 12) + d; h = Mur(b ^ seed, h) + a; return fmix(h); } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L1053-L1059 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe uint Hash32Len5to12(byte* s, uint len, uint seed = 0) { uint a = len, b = len * 5, c = 9, d = b + seed; a += Fetch(s); b += Fetch(s + len - 4); c += Fetch(s + ((len >> 1) & 4)); return fmix(seed ^ Mur(c, Mur(b, Mur(a, d)))); } /// <summary> /// Calculates a 32bit hash from a given byte array upto a certain length /// </summary> /// <param name="s">pointer to bytes that contain at least <paramref name="len"/> bytes</param> /// <param name="length">number of bytes to consume to calculate hash</param> /// <returns>A 32bit hash</returns> // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L1061-L1117 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe uint Hash32(byte* s, int length) { uint len = (uint)length; if (len <= 24) { return len <= 12 ? (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len)) : Hash32Len13to24(s, len); } uint h = len, g = c1 * len, f = g; uint a0 = Rotate(Fetch(s + len - 4) * c1, 17) * c2; uint a1 = Rotate(Fetch(s + len - 8) * c1, 17) * c2; uint a2 = Rotate(Fetch(s + len - 16) * c1, 17) * c2; uint a3 = Rotate(Fetch(s + len - 12) * c1, 17) * c2; uint a4 = Rotate(Fetch(s + len - 20) * c1, 17) * c2; h ^= a0; h = Rotate(h, 19); h = h * 5 + 0xe6546b64; h ^= a2; h = Rotate(h, 19); h = h * 5 + 0xe6546b64; g ^= a1; g = Rotate(g, 19); g = g * 5 + 0xe6546b64; g ^= a3; g = Rotate(g, 19); g = g * 5 + 0xe6546b64; f += a4; f = Rotate(f, 19) + 113; uint iters = (len - 1) / 20; do { uint a = Fetch(s); uint b = Fetch(s + 4); uint c = Fetch(s + 8); uint d = Fetch(s + 12); uint e = Fetch(s + 16); h += a; g += b; f += c; h = Mur(d, h) + e; g = Mur(c, g) + a; f = Mur(b + e * c1, f) + d; f += g; g += f; s += 20; } while (--iters != 0); g = Rotate(g, 11) * c1; g = Rotate(g, 17) * c1; f = Rotate(f, 11) * c1; f = Rotate(f, 17) * c1; h = Rotate(h + g, 19); h = h * 5 + 0xe6546b64; h = Rotate(h, 17) * c1; h = Rotate(h + f, 19); h = h * 5 + 0xe6546b64; h = Rotate(h, 17) * c1; return h; } /// <summary> /// Calculates a 32bit hash from a given byte array upto a certain length /// </summary> /// <param name="s">Byte array to calculate the hash on</param> /// <param name="length">Number of bytes from the buffer to calculate the hash with</param> /// <returns>A 32bit hash</returns> public static unsafe uint Hash32(byte[] s, int length) { fixed (byte* buf = s) { return Hash32(buf, length); } } /// <summary> /// Calculates a 32bit hash from a given string. /// <para> /// See the /// <see href="/articles/guides/strings.html">article on strings</see> /// for longform explanation /// </para> /// </summary> /// <param name="s">String to hash</param> /// <returns>A 32bit hash</returns> public static unsafe uint Hash32(string s) { fixed (char* buffer = s) { return Hash32((byte*)buffer, s.Length * sizeof(char)); } } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.h#L70 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint128_t Uint128(ulong lo, ulong hi) => new uint128_t(lo, hi); // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L417-L419 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ulong ShiftMix(ulong val) => val ^ val >> 47; // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L425-L433 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ulong HashLen16(ulong u, ulong v, ulong mul) { // Murmur-inspired hashing. ulong a = (u ^ v) * mul; a ^= a >> 47; ulong b = (v ^ a) * mul; b ^= b >> 47; b *= mul; return b; } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L472-L483 // Return a 16-byte hash for 48 bytes. Quick and dirty. // Callers do best to use "random-looking" values for a and b. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint128_t WeakHashLen32WithSeeds( ulong w, ulong x, ulong y, ulong z, ulong a, ulong b) { a += w; b = Rotate64(b + a + z, 21); ulong c = a; a += x; a += y; b += Rotate64(a, 44); return Uint128(a + z, b + c); } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L485-L494 // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe uint128_t WeakHashLen32WithSeeds( byte* s, ulong a, ulong b) { return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a, b); } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L1710-L1733 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe ulong HashLen0to16(byte* s, uint len) { if (len >= 8) { ulong mul = k2 + len * 2; ulong a = Fetch64(s) + k2; ulong b = Fetch64(s + len - 8); ulong c = Rotate64(b, 37) * mul + a; ulong d = (Rotate64(a, 25) + b) * mul; return HashLen16(c, d, mul); } if (len >= 4) { ulong mul = k2 + len * 2; ulong a = Fetch32(s); return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul); } if (len > 0) { ushort a = s[0]; ushort b = s[len >> 1]; ushort c = s[len - 1]; uint y = a + ((uint)b << 8); uint z = len + ((uint)c << 2); return ShiftMix(y * k2 ^ z * k0) * k2; } return k2; } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L460-L470 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe ulong HashLen17to32(byte* s, uint len) { ulong mul = k2 + len * 2; ulong a = Fetch64(s) * k1; ulong b = Fetch64(s + 8); ulong c = Fetch64(s + len - 8) * mul; ulong d = Fetch64(s + len - 16) * k2; return HashLen16(Rotate64(a + b, 43) + Rotate64(c, 30) + d, a + Rotate64(b + k2, 18) + c, mul); } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L585-L590 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ulong H(ulong x, ulong y, ulong mul, int r) { ulong a = (x ^ y) * mul; a ^= a >> 47; ulong b = (y ^ a) * mul; return Rotate64(b, r) * mul; } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L700-L711 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe ulong H32(byte* s, uint len, ulong mul, ulong seed0 = 0, ulong seed1 = 0) { ulong a = Fetch64(s) * k1; ulong b = Fetch64(s + 8); ulong c = Fetch64(s + len - 8) * mul; ulong d = Fetch64(s + len - 16) * k2; ulong u = Rotate64(a + b, 43) + Rotate64(c, 30) + d + seed0; ulong v = a + Rotate64(b + k2, 18) + c + seed1; a = ShiftMix((u ^ v) * mul); b = ShiftMix((v ^ a) * mul); return b; } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L713-L720 // Return an 8-byte hash for 33 to 64 bytes. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe ulong HashLen33to64(byte* s, uint len) { const ulong mul0 = k2 - 30; ulong mul1 = k2 - 30 + 2 * len; ulong h0 = H32(s, 32, mul0); ulong h1 = H32(s + len - 32, 32, mul1); return (h1 * mul1 + h0) * mul1; } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L722-L730 // Return an 8-byte hash for 65 to 96 bytes. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe ulong HashLen65to96(byte* s, uint len) { const ulong mul0 = k2 - 114; ulong mul1 = k2 - 114 + 2 * len; ulong h0 = H32(s, 32, mul0); ulong h1 = H32(s + 32, 32, mul1); ulong h2 = H32(s + len - 32, 32, mul1, h0, h1); return (h2 * 9 + (h0 >> 17) + (h1 >> 21)) * mul1; } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L592-L681 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe ulong Hash64_uo(byte* s, uint len) { const ulong seed0 = 81; const ulong seed1 = 0; // For strings over 64 bytes we loop. Internal state consists of // 64 bytes: u, v, w, x, y, and z. ulong x = seed0; ulong y = seed1 * k2 + 113; ulong z = ShiftMix(y * k2) * k2; // v and w used to be uint128_t(seed0, seed1), uint128_t(0, 0), but // using only primitives meant a 40% performance increase, hence the // deviation with original farmhash algorithm; see commit 380c059 ulong v_first = seed0; ulong v_second = seed1; ulong w_first = 0; ulong w_second = 0; ulong u = x - z; x *= k2; ulong mul = k2 + (u & 0x82); // Set end so that after the loop we have 1 to 64 bytes left to process. byte* end = s + (len - 1) / 64 * 64; byte* last64 = end + ((len - 1) & 63) - 63; do { ulong a0 = Fetch64(s); ulong a1 = Fetch64(s + 8); ulong a2 = Fetch64(s + 16); ulong a3 = Fetch64(s + 24); ulong a4 = Fetch64(s + 32); ulong a5 = Fetch64(s + 40); ulong a6 = Fetch64(s + 48); ulong a7 = Fetch64(s + 56); x += a0 + a1; y += a2; z += a3; v_first += a4; v_second += a5 + a1; w_first += a6; w_second += a7; x = Rotate64(x, 26); x *= 9; y = Rotate64(y, 29); z *= mul; v_first = Rotate64(v_first, 33); v_second = Rotate64(v_second, 30); w_first ^= x; w_first *= 9; z = Rotate64(z, 32); z += w_second; w_second += z; z *= 9; ulong tmp = u; u = y; y = tmp; z += a0 + a6; v_first += a2; v_second += a3; w_first += a4; w_second += a5 + a6; x += a1; y += a7; y += v_first; v_first += x - y; v_second += w_first; w_first += v_second; w_second += x - y; x += w_second; w_second = Rotate64(w_second, 34); tmp = u; u = z; z = tmp; s += 64; } while (s != end); // Make s point to the last 64 bytes of input. s = last64; u *= 9; v_second = Rotate64(v_second, 28); v_first = Rotate64(v_first, 20); w_first += (len - 1) & 63; u += y; y += u; x = Rotate64(y - x + v_first + Fetch64(s + 8), 37) * mul; y = Rotate64(y ^ v_second ^ Fetch64(s + 48), 42) * mul; x ^= w_second * 9; y += v_first + Fetch64(s + 40); z = Rotate64(z + w_first, 33) * mul; uint128_t v = WeakHashLen32WithSeeds(s, v_second * mul, x + w_first); uint128_t w = WeakHashLen32WithSeeds(s + 32, z + w_second, y + Fetch64(s + 16)); return H(HashLen16(v.first + x, w.first ^ y, mul) + z - u, H(v.second + y, w.second + z, k2, 30) ^ x, k2, 31); } // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L513-L566 // Return an 8-byte hash for 65 to 96 bytes. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe ulong Hash64_na(byte* s, uint len) { const ulong seed = 81; // For strings over 64 bytes we loop. Internal state consists of // 56 bytes: v, w, x, y, and z. ulong x = seed; ulong y = unchecked(seed * k1 + 113); ulong z = ShiftMix(y * k2 + 113) * k2; uint128_t v = Uint128(0, 0); uint128_t w = Uint128(0, 0); x = x * k2 + Fetch64(s); ulong tmp; // Set end so that after the loop we have 1 to 64 bytes left to process. byte* end = s + (len - 1) / 64 * 64; byte* last64 = end + ((len - 1) & 63) - 63; do { x = Rotate64(x + y + v.first + Fetch64(s + 8), 37) * k1; y = Rotate64(y + v.second + Fetch64(s + 48), 42) * k1; x ^= w.second; y += v.first + Fetch64(s + 40); z = Rotate64(z + w.first, 33) * k1; v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); tmp = z; z = x; x = tmp; s += 64; } while (s != end); ulong mul = k1 + ((z & 0xff) << 1); // Make s point to the last 64 bytes of input. s = last64; w.first += (len - 1) & 63; v.first += w.first; w.first += v.first; x = Rotate64(x + y + v.first + Fetch64(s + 8), 37) * mul; y = Rotate64(y + v.second + Fetch64(s + 48), 42) * mul; x ^= w.second * 9; y += v.first * 9 + Fetch64(s + 40); z = Rotate64(z + w.first, 33) * mul; v = WeakHashLen32WithSeeds(s, v.second * mul, x + w.first); w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); tmp = z; z = x; x = tmp; return HashLen16(HashLen16(v.first, w.first, mul) + ShiftMix(y) * k0 + z, HashLen16(v.second, w.second, mul) + x, mul); } /// <summary> /// Calculates a 64bit hash from a given byte array upto a certain length /// </summary> /// <param name="s">pointer to bytes that contain at least <paramref name="len"/> bytes</param> /// <param name="length">number of bytes to consume to calculate hash</param> /// <returns>A 64bit hash</returns> // https://github.com/google/farmhash/blob/34c13ddfab0e35422f4c3979f360635a8c050260/src/farmhash.cc#L732-L748 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe ulong Hash64(byte* s, int length) { uint len = (uint)length; if (len <= 32) { // NOTE: Do not try and optimize HashLen0to16 to use an unfixed // byte buffer. It increased hash times dramatically. Last attempted: // 2017-07-09. Maybe .NET has improved in speed for fixing arrays? return len <= 16 ? HashLen0to16(s, len) : HashLen17to32(s, len); } if (len <= 64) { return HashLen33to64(s, len); } if (len <= 96) { return HashLen65to96(s, len); } return len <= 256 ? Hash64_na(s, len) : Hash64_uo(s, len); } /// <summary> /// Calculates a 64bit hash from a given byte array upto a certain length /// </summary> /// <param name="s">Byte array to calculate the hash on</param> /// <param name="length">Number of bytes from the buffer to calculate the hash with</param> /// <returns>A 64bit hash</returns> public static unsafe ulong Hash64(byte[] s, int length) { fixed (byte* buf = s) { return Hash64(buf, length); } } /// <summary> /// Calculates a 64bit hash from a given string. /// <para> /// See the /// <see href="/articles/guides/strings.html">article on strings</see> /// for longform explanation /// </para> /// </summary> /// <param name="s">String to hash</param> /// <returns>A 64bit hash</returns> public static unsafe ulong Hash64(string s) { fixed (char* buffer = s) { return Hash64((byte*)buffer, s.Length * sizeof(char)); } } /// <summary> /// Calculates the 32bit from a readonly span of byte data /// </summary> /// <param name="span">span of data to hash</param> /// <returns>A 32bit hash</returns> public static unsafe uint Hash32(ReadOnlySpan<byte> span) { fixed (byte* buf = span) { return Hash32(buf, span.Length); } } /// <summary> /// Calculates the 64bit from a readonly span of byte data /// </summary> /// <param name="span">span of data to hash</param> /// <returns>A 64bit hash</returns> public static unsafe ulong Hash64(ReadOnlySpan<byte> span) { fixed (byte* buf = span) { return Hash64(buf, span.Length); } } } }