Esempio n. 1
0
        /// <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>()));
        }
Esempio n. 2
0
        /// <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>());
 }