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)); }
/// <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); }
/// <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))); }
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); }
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; } }
/// <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); }
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; } }
/// <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(); } } } }
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)); }
public ReadOnlySpan <T> Slice(int start) { Contract.RequiresInInclusiveRange(start, (uint)Length); return(new ReadOnlySpan <T>( Object, Offset + (start * UnsafeUtilities.SizeOf <T>()), Length - start)); }
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); }
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)); }
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)); }