/// <summary> /// Determines whether two spans are structurally (byte-wise) equal by comparing the elements by using memcmp /// </summary> /// <param name="first">A span, of type T to compare to second.</param> /// <param name="second">A span, of type U to compare to first.</param> public static bool BlockEquals <[Primitive] T, [Primitive] U>(this ReadOnlySpan <T> first, ReadOnlySpan <U> second) where T : struct where U : struct { var bytesCount = (ulong)first.Length * (ulong)Unsafe.SizeOf <T>(); if (bytesCount != (ulong)second.Length * (ulong)Unsafe.SizeOf <U>()) { return(false); } // perf: it is cheaper to compare 'n' long elements than 'n*8' bytes (in a loop) if ((bytesCount & 0x00000007) == 0) // fast % sizeof(long) { return(SequenceEqual(first.NonPortableCast <T, long>(), second.NonPortableCast <U, long>())); } if ((bytesCount & 0x00000003) == 0) // fast % sizeof(int) { return(SequenceEqual(first.NonPortableCast <T, int>(), second.NonPortableCast <U, int>())); } if ((bytesCount & 0x00000001) == 0) // fast % sizeof(short) { return(SequenceEqual(first.NonPortableCast <T, short>(), second.NonPortableCast <U, short>())); } return(SpanExtensions.SequenceEqual(first.NonPortableCast <T, byte>(), second.NonPortableCast <U, byte>())); }
/// <summary> /// Computes a 64-hash using the Marvin algorithm. /// </summary> public static long ComputeHash(ReadOnlySpan <byte> data, ulong seed) { uint p0 = (uint)seed; uint p1 = (uint)(seed >> 32); if (data.Length >= sizeof(uint)) { ReadOnlySpan <uint> uData = data.NonPortableCast <byte, uint>(); for (int i = 0; i < uData.Length; i++) { p0 += uData[i]; Block(ref p0, ref p1); } // byteOffset = data.Length - data.Length % 4 // is equivalent to clearing last 2 bits of length // Using it directly gives a perf hit for short strings making it at least 5% or more slower. int byteOffset = data.Length & (~3); data = data.Slice(byteOffset); } switch (data.Length) { case 0: p0 += 0x80u; break; case 1: p0 += 0x8000u | data[0]; break; case 2: p0 += 0x800000u | data.NonPortableCast <byte, ushort>()[0]; break; case 3: p0 += 0x80000000u | (((uint)data[2]) << 16) | (uint)(data.NonPortableCast <byte, ushort>()[0]); break; default: Debug.Fail("Should not get here."); break; } Block(ref p0, ref p1); Block(ref p0, ref p1); return((((long)p1) << 32) | p0); }
public static ReadOnlySpan <U> Cast <[Primitive] T, [Primitive] U>(this ReadOnlySpan <T> slice) where T : struct where U : struct { return(slice.NonPortableCast <T, U>()); }