Exemple #1
0
        public static ReadOnlySpan <U> Cast <[Primitive] T, [Primitive] U>(this ReadOnlySpan <T> slice)
            where T : struct
            where U : struct
        {
            int countOfU;

            /// This comparison is a jittime constant
            if (UnsafeUtilities.SizeOf <T>() > UnsafeUtilities.SizeOf <U>())
            {
                IntPtr count = UnsafeUtilities.CountOfU <T, U>((uint)slice.Length);
                unsafe
                {
                    // We can't compare IntPtrs, so have to resort to pointer comparison
                    bool fits = (byte *)count <= (byte *)int.MaxValue;
                    Contract.Requires(fits);
                    countOfU = (int)count.ToPointer();
                }
            }
            else
            {
                countOfU = slice.Length * UnsafeUtilities.SizeOf <T>() / UnsafeUtilities.SizeOf <U>();
            }

            object  obj    = slice.Object;
            UIntPtr offset = slice.Offset;

            if (countOfU == 0)
            {
                obj    = null;
                offset = (UIntPtr)0;
            }

            return(new ReadOnlySpan <U>(obj, offset, countOfU));
        }
Exemple #2
0
        /// <summary>
        /// Copies the contents of this span into another.  The destination
        /// must be at least as big as the source, and may be bigger.
        /// </summary>
        /// <param name="destination">The span to copy items into.</param>
        public bool TryCopyTo(Span <T> destination)
        {
            // There are some benefits of making local copies. See https://github.com/dotnet/coreclr/issues/5556
            var dest = destination;
            var src  = this;

            if (src.Length > dest.Length)
            {
                return(false);
            }

            if (default(T) != null && MemoryUtils.IsPrimitiveValueType <T>())
            {
                UnsafeUtilities.CopyBlock(src.Object, src.Offset, dest.Object, dest.Offset,
                                          src.Length * UnsafeUtilities.SizeOf <T>());
            }
            else
            {
                for (int i = 0; i < src.Length; i++)
                {
                    // We don't check bounds here as we are surely within them
                    T value = UnsafeUtilities.Get <T>(src.Object, src.Offset, (UIntPtr)i);
                    UnsafeUtilities.Set(dest.Object, dest.Offset, (UIntPtr)i, value);
                }
            }

            return(true);
        }
Exemple #3
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 = first.Length * UnsafeUtilities.SizeOf <T>();

            if (bytesCount != second.Length * UnsafeUtilities.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(Cast <T, long>(first), Cast <U, long>(second)));
            }
            if ((bytesCount & 0x00000003) == 0) // fast % sizeof(int)
            {
                return(SequenceEqual(Cast <T, int>(first), Cast <U, int>(second)));
            }
            if ((bytesCount & 0x00000001) == 0) // fast % sizeof(short)
            {
                return(SequenceEqual(Cast <T, short>(first), Cast <U, short>(second)));
            }

            return(SequenceEqual(Cast <T, byte>(first), Cast <U, byte>(second)));
        }
Exemple #4
0
        public unsafe bool TryGetArray(void *dummy, out ArraySegment <T> array)
        {
            var a = Object as T[];

            if (a == null)
            {
                array = new ArraySegment <T>();
                return(false);
            }

            var offsetToData = SpanHelpers <T> .OffsetToArrayData;

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

            array = new ArraySegment <T>(a, index, Length);
            return(true);
        }
Exemple #5
0
 public ReadOnlySpan(T[] array, int start, int length)
 {
     Contract.Requires(array != null);
     Contract.RequiresInInclusiveRange(start, length, (uint)array.Length);
     if (start < array.Length)
     {
         Object = array;
         Offset = new UIntPtr(
             (uint)(SpanHelpers <T> .OffsetToArrayData + (start * UnsafeUtilities.SizeOf <T>())));
         Length = length;
     }
     else
     {
         Object = null;
         Offset = UIntPtr.Zero;
         Length = 0;
     }
 }
Exemple #6
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);
        }
Exemple #7
0
 internal Span(T[] array, int start)
 {
     Contract.Requires(array != null);
     Contract.Requires(default(T) != null || array.GetType() == typeof(T[]));
     Contract.RequiresInInclusiveRange(start, (uint)array.Length);
     if (start < array.Length)
     {
         Object = array;
         Offset = new UIntPtr(
             (uint)(SpanHelpers <T> .OffsetToArrayData + (start * UnsafeUtilities.SizeOf <T>())));
         Length = array.Length - start;
     }
     else
     {
         Object = null;
         Offset = UIntPtr.Zero;
         Length = 0;
     }
 }
Exemple #8
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();
                    }
                }
            }
        }
Exemple #9
0
 public ReadOnlySpan <T> Slice(uint start, uint length)
 {
     Contract.RequiresInInclusiveRange(start, length, (uint)Length);
     return(new ReadOnlySpan <T>(
                Object, Offset + (((int)start) * UnsafeUtilities.SizeOf <T>()), (int)length));
 }
Exemple #10
0
 public ReadOnlySpan <T> Slice(int start)
 {
     Contract.RequiresInInclusiveRange(start, (uint)Length);
     return(new ReadOnlySpan <T>(
                Object, Offset + (start * UnsafeUtilities.SizeOf <T>()), Length - start));
 }
Exemple #11
0
 public static void Write <[Primitive] T>(this Span <byte> slice, T value)
     where T : struct
 {
     Contract.RequiresInInclusiveRange(UnsafeUtilities.SizeOf <T>(), (uint)slice.Length);
     UnsafeUtilities.Set(slice.Object, slice.Offset, (UIntPtr)0, value);
 }
Exemple #12
0
 public static T Read <[Primitive] T>(this ReadOnlySpan <byte> slice)
     where T : struct
 {
     Contract.RequiresInInclusiveRange(UnsafeUtilities.SizeOf <T>(), (uint)slice.Length);
     return(UnsafeUtilities.Get <T>(slice.Object, slice.Offset, (UIntPtr)0));
 }
Exemple #13
0
 public Span <T> Slice(int start, int length)
 {
     Contract.RequiresInInclusiveRange(start, length, (uint)Length);
     return(new Span <T>(
                Object, Offset + (start * UnsafeUtilities.SizeOf <T>()), length));
 }