/// <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>())
            {
                PtrUtils.CopyBlock(src.Object, src.Offset, dest.Object, dest.Offset,
                                   src.Length * PtrUtils.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 = PtrUtils.Get <T>(src.Object, src.Offset, (UIntPtr)i);
                    PtrUtils.Set(dest.Object, dest.Offset, (UIntPtr)i, value);
                }
            }

            return(true);
        }
示例#2
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 (PtrUtils.SizeOf <T>() > PtrUtils.SizeOf <U>())
            {
                IntPtr count = PtrUtils.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 * PtrUtils.SizeOf <T>() / PtrUtils.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));
        }
示例#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 * PtrUtils.SizeOf <T>();

            if (bytesCount != second.Length * PtrUtils.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)));
        }
示例#4
0
        /// <summary>
        /// Writes a structure of type T into a slice of bytes.
        /// </summary>
        public static void Write <[Primitive] T>(this Span <byte> slice, T value)
            where T : struct
        {
            Contract.Requires(slice.Length >= PtrUtils.SizeOf <T>());
            var cast = slice.Cast <byte, T>();

            cast[0] = value;
        }
示例#5
0
        public static Span <U> Cast <[Primitive] T, [Primitive] U>(this Span <T> slice)
            where T : struct
            where U : struct
        {
            int countOfU = slice.Length * PtrUtils.SizeOf <T>() / PtrUtils.SizeOf <U>();

            if (countOfU == 0)
            {
                return(default(Span <U>));
            }
            return(new Span <U>(slice.Object, slice.Offset, countOfU));
        }
示例#6
0
 /// <summary>
 /// Fetches the element at the specified index.
 /// </summary>
 /// <exception cref="System.ArgumentOutOfRangeException">
 /// Thrown when the specified index is not in range (&lt;0 or &gt;&eq;length).
 /// </exception>
 public T this[int index]
 {
     get {
         Contract.RequiresInRange(index, Length);
         return(PtrUtils.Get <T>(
                    m_object, m_offset + (index * PtrUtils.SizeOf <T>())));
     }
     set {
         Contract.RequiresInRange(index, Length);
         PtrUtils.Set <T>(
             m_object, m_offset + (index * PtrUtils.SizeOf <T>()), value);
     }
 }
示例#7
0
        public static ReadOnlySpan <U> Cast <[Primitive] T, [Primitive] U>(this ReadOnlySpan <T> slice)
            where T : struct
            where U : struct
        {
            int     countOfU = slice.Length * PtrUtils.SizeOf <T>() / PtrUtils.SizeOf <U>();
            object  obj      = null;
            UIntPtr offset   = default(UIntPtr);

            if (countOfU != 0)
            {
                obj    = slice.Object;
                offset = slice.Offset;
            }
            return(new ReadOnlySpan <U>(obj, offset, countOfU));
        }
 /// <summary>
 /// Fetches the element at the specified index.
 /// </summary>
 /// <exception cref="System.ArgumentOutOfRangeException">
 /// Thrown when the specified index is not in range (&lt;0 or &gt;&eq;length).
 /// </exception>
 public T this[int index]
 {
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     get
     {
         Contract.RequiresInRange(index, (uint)Length);
         return(PtrUtils.Get <T>(Object, Offset, (UIntPtr)index));
     }
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     private set
     {
         Contract.RequiresInRange(index, (uint)Length);
         PtrUtils.Set(Object, Offset, (UIntPtr)index, value);
     }
 }
示例#9
0
        /// <summary>
        /// Gets array if the slice is over an array
        /// </summary>
        /// <param name="dummy">dummy is just to make the call unsafe; feel free to pass void</param>
        /// <param name="array"></param>
        /// <returns>true if it's a span over an array; otherwise false (if over a pointer)</returns>
        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) / PtrUtils.SizeOf <T>());

            array = new ArraySegment <T>(a, index, Length);
            return(true);
        }
示例#10
0
 /// <summary>
 /// Fetches the element at the specified index.
 /// </summary>
 /// <exception cref="System.ArgumentOutOfRangeException">
 /// Thrown when the specified index is not in range (&lt;0 or &gt;&eq;length).
 /// </exception>
 public T this[int index]
 {
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     get
     {
         Contract.RequiresInRange(index, Length);
         return(PtrUtils.Get <T>(
                    _object, _offset + (index * PtrUtils.SizeOf <T>())));
     }
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     set
     {
         Contract.RequiresInRange(index, Length);
         PtrUtils.Set <T>(
             _object, _offset + (index * PtrUtils.SizeOf <T>()), value);
     }
 }
示例#11
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</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 = PtrUtils.ComputeAddress(Object, Offset).ToPointer();
                return(false);
            }

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

            array   = new ArraySegment <T>(a, index, Length);
            pointer = null;
            return(true);
        }
示例#12
0
 /// <summary>
 /// Creates a new span over the portion of the target array beginning
 /// at 'start' index.
 /// </summary>
 /// <param name="array">The target array.</param>
 /// <param name="start">The index at which to begin the span.</param>
 /// <exception cref="System.ArgumentException">
 /// Thrown if the 'array' parameter is null.
 /// </exception>
 /// <exception cref="System.ArgumentOutOfRangeException">
 /// Thrown when the specified start index is not in range (&lt;0 or &gt;&eq;length).
 /// </exception>
 // TODO: Should we have this overload? It is really confusing when you also have Span(T* array, int length)
 //       While with Slice it makes sense it might not in here.
 internal Span(T[] array, int start)
 {
     Contract.Requires(array != null);
     Contract.RequiresInInclusiveRange(start, array.Length);
     if (start < array.Length)
     {
         _object = array;
         _offset = new UIntPtr(
             (uint)(SpanHelpers <T> .OffsetToArrayData + (start * PtrUtils.SizeOf <T>())));
         Length = array.Length - start;
     }
     else
     {
         _object = null;
         _offset = UIntPtr.Zero;
         Length  = 0;
     }
 }
示例#13
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 * PtrUtils.SizeOf <T>())));
         Length = length;
     }
     else
     {
         Object = null;
         Offset = UIntPtr.Zero;
         Length = 0;
     }
 }
示例#14
0
 /// <summary>
 /// Creates a new slice over the portion of the target array beginning
 /// at 'start' index and ending at 'end' index (exclusive).
 /// </summary>
 /// <param name="array">The target array.</param>
 /// <param name="start">The index at which to begin the slice.</param>
 /// <param name="end">The index at which to end the slice (exclusive).</param>
 /// <exception cref="System.ArgumentException">
 /// Thrown if the 'array' parameter is null.
 /// </exception>
 /// <exception cref="System.ArgumentOutOfRangeException">
 /// Thrown when the specified start or end index is not in range (&lt;0 or &gt;&eq;length).
 /// </exception>
 public Slice(T[] array, int start, int end)
 {
     Contract.Requires(array != null);
     Contract.RequiresInInclusiveRange(start, array.Length);
     if (start < array.Length)
     {
         m_object = array;
         m_offset = new UIntPtr(
             (uint)(SliceHelpers <T> .OffsetToArrayData + (start * PtrUtils.SizeOf <T>())));
         Length = end - start;
     }
     else
     {
         m_object = null;
         m_offset = UIntPtr.Zero;
         Length   = 0;
     }
 }
示例#15
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 * PtrUtils.SizeOf <T>())));
         Length = array.Length - start;
     }
     else
     {
         Object = null;
         Offset = UIntPtr.Zero;
         Length = 0;
     }
 }
示例#16
0
        public void Set(ReadOnlySpan <T> values)
        {
            if (Length < values.Length)
            {
                throw new ArgumentOutOfRangeException("values");
            }

            // For native memory, use bulk copy
            if (Object == null && values.Object == null)
            {
                var source      = PtrUtils.ComputeAddress(values.Object, values.Offset);
                var destination = PtrUtils.ComputeAddress(Object, Offset);
                var byteCount   = values.Length * PtrUtils.SizeOf <T>();
                PtrUtils.Copy(source, destination, byteCount);
                return;
            }

            for (int i = 0; i < values.Length; i++)
            {
                this[i] = values[i];
            }
        }
示例#17
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)
        {
            if (Length > destination.Length)
            {
                return(false);
            }

            // For native memory, use bulk copy
            if (Object == null && destination.Object == null)
            {
                var source         = PtrUtils.ComputeAddress(Object, Offset);
                var destinationPtr = PtrUtils.ComputeAddress(destination.Object, destination.Offset);
                var byteCount      = Length * PtrUtils.SizeOf <T>();
                PtrUtils.Copy(source, destinationPtr, byteCount);
                return(true);
            }

            for (int i = 0; i < Length; i++)
            {
                destination[i] = this[i];
            }
            return(true);
        }
示例#18
0
 public ReadOnlySpan <T> Slice(int start)
 {
     Contract.RequiresInInclusiveRange(start, (uint)Length);
     return(new ReadOnlySpan <T>(
                Object, Offset + (start * PtrUtils.SizeOf <T>()), Length - start));
 }
示例#19
0
 public Span <T> Slice(int start, int length)
 {
     Contract.RequiresInInclusiveRange(start, length, (uint)Length);
     return(new Span <T>(
                Object, Offset + (start * PtrUtils.SizeOf <T>()), length));
 }
示例#20
0
 /// <summary>
 /// Reads a structure of type T out of a slice of bytes.
 /// </summary>
 public static T Read <[Primitive] T>(this Span <byte> slice)
     where T : struct
 {
     Contract.Requires(slice.Length >= PtrUtils.SizeOf <T>());
     return(slice.Cast <byte, T>()[0]);
 }
示例#21
0
 public static void Write <[Primitive] T>(this Span <byte> slice, T value)
     where T : struct
 {
     Contract.RequiresInInclusiveRange(PtrUtils.SizeOf <T>(), (uint)slice.Length);
     PtrUtils.Set(slice.Object, slice.Offset, (UIntPtr)0, value);
 }
示例#22
0
 public static T Read <[Primitive] T>(this ReadOnlySpan <byte> slice)
     where T : struct
 {
     Contract.RequiresInInclusiveRange(PtrUtils.SizeOf <T>(), (uint)slice.Length);
     return(PtrUtils.Get <T>(slice.Object, slice.Offset, (UIntPtr)0));
 }
示例#23
0
 internal T GetItemWithoutBoundariesCheck(int index)
 {
     return(PtrUtils.Get <T>(
                _object, _offset + (index * PtrUtils.SizeOf <T>())));
 }
示例#24
0
 public static T Read <[Primitive] T>(this Span <byte> slice)
     where T : struct
 {
     Contract.Requires(slice.Length >= PtrUtils.SizeOf <T>());
     return(PtrUtils.Get <T>(slice.Object, slice.Offset, (UIntPtr)0));
 }
示例#25
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
        {
            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 *)PtrUtils.ComputeAddress(first.Object, first.Offset).ToPointer();
                    byte *secondPointer = (byte *)PtrUtils.ComputeAddress(second.Object, second.Offset).ToPointer();

                    int   step              = sizeof(void *) * 5;
                    int   totalBytesCount   = first.Length * PtrUtils.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();
                    }
                }
            }
        }
示例#26
0
 internal T GetItemWithoutBoundariesCheck(int index)
 {
     return(PtrUtils.Get <T>(Object, Offset, (UIntPtr)index));
 }
示例#27
0
 public Span <T> Slice(uint start)
 {
     Contract.RequiresInInclusiveRange(start, (uint)Length);
     return(new Span <T>(Object, Offset + (((int)start) * PtrUtils.SizeOf <T>()), Length - (int)start));
 }
示例#28
0
 public ReadOnlySpan <T> Slice(uint start, uint length)
 {
     Contract.RequiresInInclusiveRange(start, length, (uint)Length);
     return(new ReadOnlySpan <T>(
                Object, Offset + (((int)start) * PtrUtils.SizeOf <T>()), (int)length));
 }
示例#29
0
 public static void Write <[Primitive] T>(this Span <byte> slice, T value)
     where T : struct
 {
     Contract.Requires(slice.Length >= PtrUtils.SizeOf <T>());
     PtrUtils.Set(slice.Object, slice.Offset, value);
 }
示例#30
0
 /// <summary>
 /// Forms a slice out of the given span, beginning at 'start', and
 /// ending at 'end' (exclusive).
 /// </summary>
 /// <param name="start">The index at which to begin this slice.</param>
 /// <param name="end">The index at which to end this slice (exclusive).</param>
 /// <exception cref="System.ArgumentOutOfRangeException">
 /// Thrown when the specified start or end index is not in range (&lt;0 or &gt;&eq;length).
 /// </exception>
 public Span <T> Slice(int start, int length)
 {
     Contract.Requires(start + length <= Length);
     return(new Span <T>(
                _object, _offset + (start * PtrUtils.SizeOf <T>()), length));
 }