/// <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); }
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)); }
/// <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))); }
/// <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; }
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)); }
/// <summary> /// Fetches the element at the specified index. /// </summary> /// <exception cref="System.ArgumentOutOfRangeException"> /// Thrown when the specified index is not in range (<0 or >&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); } }
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 (<0 or >&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); } }
/// <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); }
/// <summary> /// Fetches the element at the specified index. /// </summary> /// <exception cref="System.ArgumentOutOfRangeException"> /// Thrown when the specified index is not in range (<0 or >&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); } }
/// <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); }
/// <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 (<0 or >&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; } }
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; } }
/// <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 (<0 or >&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; } }
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; } }
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]; } }
/// <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); }
public ReadOnlySpan <T> Slice(int start) { Contract.RequiresInInclusiveRange(start, (uint)Length); return(new ReadOnlySpan <T>( Object, Offset + (start * PtrUtils.SizeOf <T>()), Length - start)); }
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)); }
/// <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]); }
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); }
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)); }
internal T GetItemWithoutBoundariesCheck(int index) { return(PtrUtils.Get <T>( _object, _offset + (index * PtrUtils.SizeOf <T>()))); }
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)); }
/// <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(); } } } }
internal T GetItemWithoutBoundariesCheck(int index) { return(PtrUtils.Get <T>(Object, Offset, (UIntPtr)index)); }
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)); }
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)); }
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); }
/// <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 (<0 or >&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)); }