예제 #1
0
        /// <summary>
        /// Gets array if the slice is over an array, otherwise gets a pointer to memory.
        /// </summary>
        /// <returns>true if it's a span over an array; otherwise false (if over a pointer)</returns>
        /// <remarks>This method can be used for interop, while we are waiting for proper pinning support. Make sure the array contents are read-only.</remarks>
        public unsafe bool TryGetArrayElseGetPointer(out ArraySegment <T> array, out void *pointer)
        {
            var a = Object as T[];

            if (a == null)
            {
                array   = new ArraySegment <T>();
                pointer = UnsafeUtilities.ComputeAddress(Object, Offset).ToPointer();
                return(false);
            }

            var offsetToData = SpanHelpers <T> .OffsetToArrayData;
            var index        = (int)((Offset.ToUInt32() - offsetToData) / UnsafeUtilities.SizeOf <T>());

            array   = new ArraySegment <T>(a, index, Length);
            pointer = null;
            return(true);
        }
예제 #2
0
        /// <summary>
        /// platform independent fast memory comparison
        /// for x64 it is as fast as memcmp of msvcrt.dll, for x86 it is up to two times faster!!
        /// </summary>
        internal static bool MemCmp <[Primitive] T>(Span <T> first, Span <T> second)
            where T : struct
        {
            if (first.Length != second.Length)
            {
                return(false);
            }

            unsafe
            {
                // prevent GC from moving memory
                var firstPinnedHandle  = GCHandle.Alloc(first.Object, GCHandleType.Pinned);
                var secondPinnedHandle = GCHandle.Alloc(second.Object, GCHandleType.Pinned);

                try
                {
                    byte *firstPointer  = (byte *)UnsafeUtilities.ComputeAddress(first.Object, first.Offset).ToPointer();
                    byte *secondPointer = (byte *)UnsafeUtilities.ComputeAddress(second.Object, second.Offset).ToPointer();

                    int   step              = sizeof(void *) * 5;
                    int   totalBytesCount   = first.Length * UnsafeUtilities.SizeOf <T>();
                    byte *firstPointerLimit = firstPointer + (totalBytesCount - step);

                    if (totalBytesCount > step)
                    {
                        while (firstPointer < firstPointerLimit)
                        {   // IMPORTANT: in order to get HUGE benefits of loop unrolling on x86 we use break instead of return
                            if (*((void **)firstPointer + 0) != *((void **)secondPointer + 0))
                            {
                                break;
                            }
                            if (*((void **)firstPointer + 1) != *((void **)secondPointer + 1))
                            {
                                break;
                            }
                            if (*((void **)firstPointer + 2) != *((void **)secondPointer + 2))
                            {
                                break;
                            }
                            if (*((void **)firstPointer + 3) != *((void **)secondPointer + 3))
                            {
                                break;
                            }
                            if (*((void **)firstPointer + 4) != *((void **)secondPointer + 4))
                            {
                                break;
                            }

                            firstPointer  += step;
                            secondPointer += step;
                        }
                        if (firstPointer < firstPointerLimit) // the upper loop ended with break;
                        {
                            return(false);
                        }
                    }
                    firstPointerLimit += step; // lets check the remaining bytes
                    while (firstPointer < firstPointerLimit)
                    {
                        if (*firstPointer != *secondPointer)
                        {
                            break;
                        }

                        ++firstPointer;
                        ++secondPointer;
                    }

                    return(firstPointer == firstPointerLimit);
                }
                finally
                {
                    if (firstPinnedHandle.IsAllocated)
                    {
                        firstPinnedHandle.Free();
                    }
                    if (secondPinnedHandle.IsAllocated)
                    {
                        secondPinnedHandle.Free();
                    }
                }
            }
        }