summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIan Hays <ianha@microsoft.com>2018-01-22 19:07:15 -0800
committerJan Kotas <jkotas@microsoft.com>2018-01-22 19:07:15 -0800
commitc69e8148e42d581ceec9fd3d8ef8d65706b14235 (patch)
tree93bcf1013337631dca0108a68d8aa79a8d9a2518 /src
parentd69118807bff88c48ace28d4befa2c41bf4e7766 (diff)
downloadcoreclr-c69e8148e42d581ceec9fd3d8ef8d65706b14235.tar.gz
coreclr-c69e8148e42d581ceec9fd3d8ef8d65706b14235.tar.bz2
coreclr-c69e8148e42d581ceec9fd3d8ef8d65706b14235.zip
Misc Span/Memory changes (#15941)
* Misc Span/Memory additions - Add MemoryMarshal.CreateSpan to replace DangerousCreate - Add MemoryMarshal.CreateReadOnlySpan to replace DangerousCreate - Add MemoryMarshal.Cast to replace NonPortableCast - Add ToString override to Span and ReadOnlySpan - Add ToEnumerable function to MemoryMarshal that takes a ReadOnlyMemory
Diffstat (limited to 'src')
-rw-r--r--src/mscorlib/shared/System.Private.CoreLib.Shared.projitems1
-rw-r--r--src/mscorlib/shared/System/Globalization/DateTimeFormat.cs3
-rw-r--r--src/mscorlib/shared/System/Globalization/TimeSpanFormat.cs3
-rw-r--r--src/mscorlib/shared/System/ReadOnlySpan.cs5
-rw-r--r--src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.Fast.cs114
-rw-r--r--src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.cs69
-rw-r--r--src/mscorlib/shared/System/Span.cs5
7 files changed, 144 insertions, 56 deletions
diff --git a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
index bfe1eec776..89d7cfd039 100644
--- a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
+++ b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
@@ -435,6 +435,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\LayoutKind.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MarshalAsAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MarshalDirectiveException.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MemoryMarshal.Fast.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MemoryMarshal.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\OptionalAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\OutAttribute.cs" />
diff --git a/src/mscorlib/shared/System/Globalization/DateTimeFormat.cs b/src/mscorlib/shared/System/Globalization/DateTimeFormat.cs
index d15cc1cc8c..595fb56313 100644
--- a/src/mscorlib/shared/System/Globalization/DateTimeFormat.cs
+++ b/src/mscorlib/shared/System/Globalization/DateTimeFormat.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
+using System.Runtime.InteropServices;
namespace System
{
@@ -703,7 +704,7 @@ namespace System
if (nextChar >= 0 && nextChar != '%')
{
char nextCharChar = (char)nextChar;
- StringBuilder origStringBuilder = FormatCustomized(dateTime, ReadOnlySpan<char>.DangerousCreate(null, ref nextCharChar, 1), dtfi, offset, result);
+ StringBuilder origStringBuilder = FormatCustomized(dateTime, MemoryMarshal.CreateReadOnlySpan<char>(ref nextCharChar, 1), dtfi, offset, result);
Debug.Assert(ReferenceEquals(origStringBuilder, result));
tokenLen = 2;
}
diff --git a/src/mscorlib/shared/System/Globalization/TimeSpanFormat.cs b/src/mscorlib/shared/System/Globalization/TimeSpanFormat.cs
index bf12b246b0..a66e4600aa 100644
--- a/src/mscorlib/shared/System/Globalization/TimeSpanFormat.cs
+++ b/src/mscorlib/shared/System/Globalization/TimeSpanFormat.cs
@@ -4,6 +4,7 @@
using System.Text;
using System.Diagnostics;
+using System.Runtime.InteropServices;
namespace System.Globalization
{
@@ -315,7 +316,7 @@ namespace System.Globalization
if (nextChar >= 0 && nextChar != (int)'%')
{
char nextCharChar = (char)nextChar;
- StringBuilder origStringBuilder = FormatCustomized(value, ReadOnlySpan<char>.DangerousCreate(null, ref nextCharChar, 1), dtfi, result);
+ StringBuilder origStringBuilder = FormatCustomized(value, MemoryMarshal.CreateReadOnlySpan<char>(ref nextCharChar, 1), dtfi, result);
Debug.Assert(ReferenceEquals(origStringBuilder, result));
tokenLen = 2;
}
diff --git a/src/mscorlib/shared/System/ReadOnlySpan.cs b/src/mscorlib/shared/System/ReadOnlySpan.cs
index 4e6339a74c..06af661d43 100644
--- a/src/mscorlib/shared/System/ReadOnlySpan.cs
+++ b/src/mscorlib/shared/System/ReadOnlySpan.cs
@@ -260,6 +260,11 @@ namespace System
}
/// <summary>
+ /// Returns a <see cref="String"/> with the name of the type and the number of elements
+ /// </summary>
+ public override string ToString() => "System.Span[" + Length.ToString() + "]";
+
+ /// <summary>
/// Defines an implicit conversion of an array to a <see cref="ReadOnlySpan{T}"/>
/// </summary>
public static implicit operator ReadOnlySpan<T>(T[] array) => array != null ? new ReadOnlySpan<T>(array) : default;
diff --git a/src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.Fast.cs b/src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.Fast.cs
new file mode 100644
index 0000000000..4e0caed6ad
--- /dev/null
+++ b/src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.Fast.cs
@@ -0,0 +1,114 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Runtime.CompilerServices;
+using System.Collections.Generic;
+using Internal.Runtime.CompilerServices;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Provides a collection of methods for interoperating with <see cref="Memory{T}"/>, <see cref="ReadOnlyMemory{T}"/>,
+ /// <see cref="Span{T}"/>, and <see cref="ReadOnlySpan{T}"/>.
+ /// </summary>
+ public static partial class MemoryMarshal
+ {
+ /// <summary>Creates a <see cref="Memory{T}"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
+ /// <param name="readOnlyMemory">The <see cref="ReadOnlyMemory{T}"/>.</param>
+ /// <returns>A <see cref="Memory{T}"/> representing the same memory as the <see cref="ReadOnlyMemory{T}"/>, but writable.</returns>
+ /// <remarks>
+ /// <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> must be used with extreme caution. <see cref="ReadOnlyMemory{T}"/> is used
+ /// to represent immutable data and other memory that is not meant to be written to; <see cref="Memory{T}"/> instances created
+ /// by <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> should not be written to. The method exists to enable variables typed
+ /// as <see cref="Memory{T}"/> but only used for reading to store a <see cref="ReadOnlyMemory{T}"/>.
+ /// </remarks>
+ public static Memory<T> AsMemory<T>(ReadOnlyMemory<T> readOnlyMemory) =>
+ Unsafe.As<ReadOnlyMemory<T>, Memory<T>>(ref readOnlyMemory);
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
+ /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
+ /// </summary>
+ public static ref T GetReference<T>(Span<T> span) => ref span._pointer.Value;
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the ReadOnlySpan. If the Span is empty, returns a reference to the location where the 0th element
+ /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
+ /// </summary>
+ public static ref T GetReference<T>(ReadOnlySpan<T> span) => ref span._pointer.Value;
+
+ /// <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> Cast<TFrom, TTo>(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> Cast<TFrom, TTo>(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>
+ /// 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 the
+ /// <paramref name="length"/> is not checked.
+ /// </summary>
+ /// <param name="reference">A reference to data.</param>
+ /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span<T> CreateSpan<T>(ref T reference, int length) => new Span<T>(ref reference, 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 the
+ /// <paramref name="length"/> is not checked.
+ /// </summary>
+ /// <param name="reference">A reference to data.</param>
+ /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<T> CreateReadOnlySpan<T>(ref T reference, int length) => new ReadOnlySpan<T>(ref reference, length);
+ }
+}
diff --git a/src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.cs b/src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.cs
index 63e301beca..cc815d0598 100644
--- a/src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.cs
+++ b/src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.cs
@@ -4,9 +4,7 @@
using System.Buffers;
using System.Runtime.CompilerServices;
-#if !FEATURE_PORTABLE_SPAN
-using Internal.Runtime.CompilerServices;
-#endif // FEATURE_PORTABLE_SPAN
+using System.Collections.Generic;
namespace System.Runtime.InteropServices
{
@@ -14,58 +12,8 @@ namespace System.Runtime.InteropServices
/// Provides a collection of methods for interoperating with <see cref="Memory{T}"/>, <see cref="ReadOnlyMemory{T}"/>,
/// <see cref="Span{T}"/>, and <see cref="ReadOnlySpan{T}"/>.
/// </summary>
- public static class MemoryMarshal
+ public static partial class MemoryMarshal
{
- /// <summary>Creates a <see cref="Memory{T}"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
- /// <param name="readOnlyMemory">The <see cref="ReadOnlyMemory{T}"/>.</param>
- /// <returns>A <see cref="Memory{T}"/> representing the same memory as the <see cref="ReadOnlyMemory{T}"/>, but writable.</returns>
- /// <remarks>
- /// <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> must be used with extreme caution. <see cref="ReadOnlyMemory{T}"/> is used
- /// to represent immutable data and other memory that is not meant to be written to; <see cref="Memory{T}"/> instances created
- /// by <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> should not be written to. The method exists to enable variables typed
- /// as <see cref="Memory{T}"/> but only used for reading to store a <see cref="ReadOnlyMemory{T}"/>.
- /// </remarks>
- public static Memory<T> AsMemory<T>(ReadOnlyMemory<T> readOnlyMemory) =>
- Unsafe.As<ReadOnlyMemory<T>, Memory<T>>(ref readOnlyMemory);
-
-#if FEATURE_PORTABLE_SPAN
- /// <summary>
- /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
- /// </summary>
- public static ref T GetReference<T>(Span<T> span)
- {
- if (span.Pinnable == null)
- unsafe { return ref Unsafe.AsRef<T>(span.ByteOffset.ToPointer()); }
- else
- return ref Unsafe.AddByteOffset<T>(ref span.Pinnable.Data, span.ByteOffset);
- }
-
- /// <summary>
- /// Returns a reference to the 0th element of the ReadOnlySpan. If the Span is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
- /// </summary>
- public static ref T GetReference<T>(ReadOnlySpan<T> span)
- {
- if (span.Pinnable == null)
- unsafe { return ref Unsafe.AsRef<T>(span.ByteOffset.ToPointer()); }
- else
- return ref Unsafe.AddByteOffset<T>(ref span.Pinnable.Data, span.ByteOffset);
- }
-#else
- /// <summary>
- /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
- /// </summary>
- public static ref T GetReference<T>(Span<T> span) => ref span._pointer.Value;
-
- /// <summary>
- /// Returns a reference to the 0th element of the ReadOnlySpan. If the Span is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
- /// </summary>
- public static ref T GetReference<T>(ReadOnlySpan<T> span) => ref span._pointer.Value;
-#endif // FEATURE_PORTABLE_SPAN
-
/// <summary>
/// Get an array segment from the underlying memory.
/// If unable to get the array segment, return false with a default array segment.
@@ -90,5 +38,18 @@ namespace System.Runtime.InteropServices
arraySegment = default;
return false;
}
+
+ /// <summary>
+ /// Creates an <see cref="IEnumerable{T}"/> view of the given <paramref name="memory" /> to allow
+ /// the <paramref name="memory" /> to be used in existing APIs that take an <see cref="IEnumerable{T}"/>.
+ /// </summary>
+ /// <typeparam name="T">The element type of the <paramref name="memory" />.</typeparam>
+ /// <param name="memory">The ReadOnlyMemory to view as an <see cref="IEnumerable{T}"/></param>
+ /// <returns>An <see cref="IEnumerable{T}"/> view of the given <paramref name="memory" /></returns>
+ public static IEnumerable<T> ToEnumerable<T>(ReadOnlyMemory<T> memory)
+ {
+ for (int i = 0; i < memory.Length; i++)
+ yield return memory.Span[i];
+ }
}
}
diff --git a/src/mscorlib/shared/System/Span.cs b/src/mscorlib/shared/System/Span.cs
index 5a813174d9..8c57ab4883 100644
--- a/src/mscorlib/shared/System/Span.cs
+++ b/src/mscorlib/shared/System/Span.cs
@@ -341,6 +341,11 @@ namespace System
}
/// <summary>
+ /// Returns a <see cref="String"/> with the name of the type and the number of elements
+ /// </summary>
+ public override string ToString() => "System.Span[" + Length.ToString() + "]";
+
+ /// <summary>
/// Defines an implicit conversion of an array to a <see cref="Span{T}"/>
/// </summary>
public static implicit operator Span<T>(T[] array) => array != null ? new Span<T>(array) : default;