_length = length;
}
- /// <summary>
- /// Create a new read-only span over a portion of a regular managed object. This can be useful
- /// if part of a managed object represents a "fixed array." This is dangerous because neither the
- /// <paramref name="length"/> is checked, nor <paramref name="obj"/> being null, nor the fact that
- /// "rawPointer" actually lies within <paramref name="obj"/>.
- /// </summary>
- /// <param name="obj">The managed object that contains the data to span over.</param>
- /// <param name="objectData">A reference to data within that object.</param>
- /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static ReadOnlySpan<T> DangerousCreate(object obj, ref T objectData, int length) => new ReadOnlySpan<T>(ref objectData, length);
-
// Constructor for internal use only.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ReadOnlySpan(ref T ptr, int length)
}
/// <summary>
- /// Casts a Span of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
- /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <remarks>
- /// Supported only for platforms that support misaligned memory access.
- /// </remarks>
- /// <param name="source">The source slice, of type <typeparamref name="TFrom"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<TTo> NonPortableCast<TFrom, TTo>(this Span<TFrom> source)
- where TFrom : struct
- where TTo : struct
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
- if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
-
- return new Span<TTo>(
- ref Unsafe.As<TFrom, TTo>(ref source.DangerousGetPinnableReference()),
- checked((int)((long)source.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
- }
-
- /// <summary>
- /// Casts a ReadOnlySpan of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
- /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <remarks>
- /// Supported only for platforms that support misaligned memory access.
- /// </remarks>
- /// <param name="source">The source slice, of type <typeparamref name="TFrom"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<TTo> NonPortableCast<TFrom, TTo>(this ReadOnlySpan<TFrom> source)
- where TFrom : struct
- where TTo : struct
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
- if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
-
- return new ReadOnlySpan<TTo>(
- ref Unsafe.As<TFrom, TTo>(ref MemoryMarshal.GetReference(source)),
- checked((int)((long)source.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
- }
-
- /// <summary>
/// Creates a new readonly span over the portion of the target string.
/// </summary>
/// <param name="text">The target string.</param>
_length = length;
}
- /// <summary>
- /// Create a new span over a portion of a regular managed object. This can be useful
- /// if part of a managed object represents a "fixed array." This is dangerous because neither the
- /// <paramref name="length"/> is checked, nor <paramref name="obj"/> being null, nor the fact that
- /// "rawPointer" actually lies within <paramref name="obj"/>.
- /// </summary>
- /// <param name="obj">The managed object that contains the data to span over.</param>
- /// <param name="objectData">A reference to data within that object.</param>
- /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static Span<T> DangerousCreate(object obj, ref T objectData, int length) => new Span<T>(ref objectData, length);
-
// Constructor for internal use only.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Span(ref T ptr, int length)
}
#endregion
- #region TestSpanDangerousCreate<T>
+ #region TestSpanCreate<T>
[Benchmark(InnerIterationCount = BaseIterations)]
[InlineData(100)]
- public static void TestSpanDangerousCreateByte(int length)
+ public static void TestSpanCreateByte(int length)
{
- InvokeTestSpanDangerousCreate<byte>(length);
+ InvokeTestSpanCreate<byte>(length);
}
[Benchmark(InnerIterationCount = BaseIterations)]
[InlineData(100)]
- public static void TestSpanDangerousCreateString(int length)
+ public static void TestSpanCreateString(int length)
{
- InvokeTestSpanDangerousCreate<string>(length);
+ InvokeTestSpanCreate<string>(length);
}
- static void InvokeTestSpanDangerousCreate<T>(int length)
+ static void InvokeTestSpanCreate<T>(int length)
{
TestClass<T> testClass = new TestClass<T>();
testClass.C0 = new T[length];
- Invoke((int innerIterationCount) => TestSpanDangerousCreate<T>(testClass, innerIterationCount, false),
- "TestSpanDangerousCreate<{0}>({1})", typeof(T).Name, length);
+ Invoke((int innerIterationCount) => TestSpanCreate<T>(testClass, innerIterationCount, false),
+ "TestSpanCreate<{0}>({1})", typeof(T).Name, length);
}
[MethodImpl(MethodImplOptions.NoInlining)]
- static void TestSpanDangerousCreate<T>(TestClass<T> testClass, int iterationCount, bool untrue)
+ static void TestSpanCreate<T>(TestClass<T> testClass, int iterationCount, bool untrue)
{
var sink = Sink<T>.Instance;
for (int i = 0; i < iterationCount; i++)
{
- var span = Span<T>.DangerousCreate(testClass, ref testClass.C0[0], testClass.C0.Length);
+ var span = MemoryMarshal.CreateSpan<T>(ref testClass.C0[0], testClass.C0.Length);
// Under a condition that we know is false but the jit doesn't,
// add a read from 'span' to make sure it's not dead, and an assignment
- // to 'testClass' so the DangerousCreate call won't get hoisted.
+ // to 'testClass' so the Create call won't get hoisted.
if (untrue) { sink.Data = span[0]; testClass = new TestClass<T>(); }
}
}
}
#endregion
- #region TestSpanNonPortableCast<T>
+ #region TestSpanCast<T>
[Benchmark(InnerIterationCount = BaseIterations)]
[InlineData(100)]
- public static void TestSpanNonPortableCastFromByteToInt(int length)
+ public static void TestSpanCastFromByteToInt(int length)
{
- InvokeTestSpanNonPortableCast<byte, int>(length);
+ InvokeTestSpanCast<byte, int>(length);
}
[Benchmark(InnerIterationCount = BaseIterations)]
[InlineData(100)]
- public static void TestSpanNonPortableCastFromIntToByte(int length)
+ public static void TestSpanCastFromIntToByte(int length)
{
- InvokeTestSpanNonPortableCast<int, byte>(length);
+ InvokeTestSpanCast<int, byte>(length);
}
- static void InvokeTestSpanNonPortableCast<From, To>(int length)
+ static void InvokeTestSpanCast<From, To>(int length)
where From : struct
where To : struct
{
var array = new From[length];
- Invoke((int innerIterationCount) => TestSpanNonPortableCast<From, To>(array, innerIterationCount, false),
- "TestSpanNonPortableCast<{0}, {1}>({2})", typeof(From).Name, typeof(To).Name, length);
+ Invoke((int innerIterationCount) => TestSpanCast<From, To>(array, innerIterationCount, false),
+ "TestSpanCast<{0}, {1}>({2})", typeof(From).Name, typeof(To).Name, length);
}
[MethodImpl(MethodImplOptions.NoInlining)]
- static void TestSpanNonPortableCast<From, To>(From[] array, int iterationCount, bool untrue)
+ static void TestSpanCast<From, To>(From[] array, int iterationCount, bool untrue)
where From : struct
where To : struct
{
for (int i = 0; i < iterationCount; i++)
{
- var toSpan = span.NonPortableCast<From, To>();
+ var toSpan = MemoryMarshal.Cast<From, To>(span);
// Under a condition that we know is false but the jit doesn't,
// add a read from 'toSpan' to make sure it's not dead, and an assignment
// to 'span' so the AsBytes call won't get hoisted.