<?xml version="1.0" encoding="utf-8"?>
<root>
- <!--
- Microsoft ResX Schema
-
+ <!--
+ Microsoft ResX Schema
+
Version 2.0
-
- The primary goals of this format is to allow a simple XML format
- that is mostly human readable. The generation and parsing of the
- various data types are done through the TypeConverter classes
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
associated with the data types.
-
+
Example:
-
+
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
-
- There are any number of "resheader" rows that contain simple
+
+ There are any number of "resheader" rows that contain simple
name/value pairs.
-
- Each data row contains a name, and value. The row also contains a
- type or mimetype. Type corresponds to a .NET class that support
- text/value conversion through the TypeConverter architecture.
- Classes that don't support this are serialized and stored with the
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
mimetype set.
-
- The mimetype is used for serialized objects, and tells the
- ResXResourceReader how to depersist the object. This is currently not
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
-
- Note - application/x-microsoft.net.object.binary.base64 is the format
- that the ResXResourceWriter will generate, however the reader can
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
-
+
mimetype: application/x-microsoft.net.object.binary.base64
- value : The object must be serialized with
+ value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
-
+
mimetype: application/x-microsoft.net.object.soap.base64
- value : The object must be serialized with
+ value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
- value : The object must be serialized into a byte array
+ value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<data name="Marshaler_StringTooLong" xml:space="preserve">
<value>Marshaler restriction: Excessively long string.</value>
</data>
+ <data name="MemoryDisposed" xml:space="preserve">
+ <value>Memory<T> has been disposed.</value>
+ </data>
<data name="MissingConstructor_Name" xml:space="preserve">
<value>Constructor on type '{0}' not found.</value>
</data>
namespace System.Buffers
{
+ /// <summary>
+ /// Provides a mechanism for manual lifetime management.
+ /// </summary>
public interface IRetainable
{
+ /// <summary>
+ /// Call this method to indicate that the IRetainable object is in use.
+ /// Do not dispose until Release is called.
+ /// </summary>
void Retain();
+ /// <summary>
+ /// Call this method to indicate that the IRetainable object is no longer in use.
+ /// The object can now be disposed.
+ /// </summary>
bool Release();
}
}
\ No newline at end of file
namespace System.Buffers
{
+ /// <summary>
+ /// A handle for the memory.
+ /// </summary>
public unsafe struct MemoryHandle : IDisposable
{
- private IRetainable _owner;
+ private IRetainable _retainable;
private void* _pointer;
private GCHandle _handle;
+ /// <summary>
+ /// Creates a new memory handle for the memory.
+ /// </summary>
+ /// <param name="retainable">reference to manually managed object</param>
+ /// <param name="pointer">pointer to memory, or null if a pointer was not provided when the handle was created</param>
+ /// <param name="handle">handle used to pin array buffers</param>
[CLSCompliant(false)]
- public MemoryHandle(IRetainable owner, void* pointer = null, GCHandle handle = default(GCHandle))
+ public MemoryHandle(IRetainable retainable, void* pointer = null, GCHandle handle = default(GCHandle))
{
- _owner = owner;
+ _retainable = retainable;
_pointer = pointer;
_handle = handle;
}
+ /// <summary>
+ /// Returns the pointer to memory, or null if a pointer was not provided when the handle was created.
+ /// </summary>
+ [CLSCompliant(false)]
+ public void* Pointer => _pointer;
+
+ /// <summary>
+ /// Returns false if the pointer to memory is null.
+ /// </summary>
+ public bool HasPointer => _pointer != null;
+
+ /// <summary>
+ /// Adds an offset to the pinned pointer.
+ /// </summary>
+ /// <exception cref="System.ArgumentNullException">
+ /// Throw when pinned pointer is null.
+ /// </exception>
internal void AddOffset(int offset)
{
if (_pointer == null)
}
}
- [CLSCompliant(false)]
- public void* Pointer => _pointer;
-
- public bool HasPointer => _pointer != null;
-
- public void Dispose()
- {
- if (_handle.IsAllocated)
+ /// <summary>
+ /// Frees the pinned handle and releases IRetainable.
+ /// </summary>
+ public void Dispose()
+ {
+ if (_handle.IsAllocated)
{
_handle.Free();
}
- if (_owner != null)
+ if (_retainable != null)
{
- _owner.Release();
- _owner = null;
+ _retainable.Release();
+ _retainable = null;
}
- _pointer = null;
+ _pointer = null;
}
-
+
}
}
\ No newline at end of file
namespace System.Buffers
{
+ /// <summary>
+ /// Owner of Memory<typeparamref name="T"/> that provides appropriate lifetime management mechanisms for it.
+ /// </summary>
public abstract class OwnedMemory<T> : IDisposable, IRetainable
{
+ /// <summary>
+ /// The number of items in the Memory<typeparamref name="T"/>.
+ /// </summary>
public abstract int Length { get; }
+ /// <summary>
+ /// Returns a span wrapping the underlying memory.
+ /// </summary>
public abstract Span<T> Span { get; }
+ /// <summary>
+ /// Returns a Memory<typeparamref name="T"/> if the underlying memory has not been freed.
+ /// </summary>
+ /// <exception cref="System.ObjectDisposedException">
+ /// Thrown when the underlying memory has already been disposed.
+ /// </exception>
public Memory<T> Memory
{
- get
+ get
{
- if (IsDisposed)
+ if (IsDisposed)
{
- ThrowHelper.ThrowObjectDisposedException(nameof(OwnedMemory<T>), ExceptionResource.Memory_ThrowIfDisposed);
+ ThrowHelper.ThrowObjectDisposedException_MemoryDisposed();
}
return new Memory<T>(owner: this, 0, Length);
}
}
+ /// <summary>
+ /// Returns a handle for the array that has been pinned and hence its address can be taken
+ /// </summary>
public abstract MemoryHandle Pin();
+ /// <summary>
+ /// Returns an array segment.
+ /// </summary>
protected internal abstract bool TryGetArray(out ArraySegment<T> arraySegment);
+ /// <summary>
+ /// Implements IDisposable.
+ /// </summary>
+ /// <exception cref="System.InvalidOperationException">
+ /// Throw when there are still retained references to the memory
+ /// </exception>
public void Dispose()
{
- if (IsRetained)
+ if (IsRetained)
{
- ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Memory_OutstandingReferences);
+ ThrowHelper.ThrowInvalidOperationException_OutstandingReferences();
}
Dispose(true);
GC.SuppressFinalize(this);
}
+ /// <summary>
+ /// Clean up of any leftover managed and unmanaged resources.
+ /// </summary>
protected abstract void Dispose(bool disposing);
+ /// <summary>
+ /// Return true if someone is holding a reference to the memory.
+ /// </summary>
protected abstract bool IsRetained { get; }
+ /// <summary>
+ /// Return true if the underlying memory has been freed.
+ /// </summary>
public abstract bool IsDisposed { get; }
+ /// <summary>
+ /// Implements IRetainable. Prevent accidental disposal of the memory.
+ /// </summary>
public abstract void Retain();
+ /// <summary>
+ /// Implements IRetainable. The memory can now be diposed.
+ /// </summary>
public abstract bool Release();
}
using System.Runtime.InteropServices;
using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
+#if !FEATURE_PORTABLE_SPAN
using Internal.Runtime.CompilerServices;
+#endif // FEATURE_PORTABLE_SPAN
namespace System
{
+ /// <summary>
+ /// Memory represents a contiguous region of arbitrary memory similar to <see cref="Span{T}"/>.
+ /// Unlike <see cref="Span{T}"/>, it is not a byref-like type.
+ /// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
[DebuggerTypeProxy(typeof(MemoryDebugView<>))]
public readonly struct Memory<T>
_index = start;
_length = length;
}
-
+
// Constructor for internal use only.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Memory(OwnedMemory<T> owner, int index, int length)
{
- if (owner == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.ownedMemory);
- if (index < 0 || length < 0)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
+ // No validation performed; caller must provide any necessary validation.
_object = owner;
_index = index | (1 << 31); // Before using _index, check if _index < 0, then 'and' it with RemoveOwnedFlagBitMask
_length = length;
/// Defines an implicit conversion of an array to a <see cref="Memory{T}"/>
/// </summary>
public static implicit operator Memory<T>(T[] array) => new Memory<T>(array);
-
+
/// <summary>
/// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="Memory{T}"/>
/// </summary>
{
ThrowHelper.ThrowArgumentOutOfRangeException();
}
-
+
return new Memory<T>(_object, _index + start, length);
}
// and then cast to a Memory<T>. Such a cast can only be done with unsafe or marshaling code,
// in which case that's the dangerous operation performed by the dev, and we're just following
// suit here to make it work as best as possible.
+#if FEATURE_PORTABLE_SPAN
+ return new Span<T>(Unsafe.As<Pinnable<T>>(s), MemoryExtensions.StringAdjustment, s.Length).Slice(_index, _length);
+#else
return new Span<T>(ref Unsafe.As<char, T>(ref s.GetRawStringData()), s.Length).Slice(_index, _length);
+#endif // FEATURE_PORTABLE_SPAN
}
else if (_object != null)
{
/// <param name="destination">The span to copy items into.</param>
public bool TryCopyTo(Memory<T> destination) => Span.TryCopyTo(destination.Span);
+ /// <summary>
+ /// Returns a handle for the array.
+ /// <param name="pin">If pin is true, the GC will not move the array and hence its address can be taken</param>
+ /// </summary>
public unsafe MemoryHandle Retain(bool pin = false)
{
MemoryHandle memoryHandle = default;
// a readable ReadOnlyMemory<char> or a writable Memory<char> can still be pinned and
// used for interop purposes.
GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
+#if FEATURE_PORTABLE_SPAN
+ void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
+#endif // FEATURE_PORTABLE_SPAN
memoryHandle = new MemoryHandle(null, pointer, handle);
}
else if (_object is T[] array)
{
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
+#if FEATURE_PORTABLE_SPAN
+ void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
+#endif // FEATURE_PORTABLE_SPAN
memoryHandle = new MemoryHandle(null, pointer, handle);
}
}
}
/// <summary>
- /// Get an array segment from the underlying memory.
+ /// Get an array segment from the underlying memory.
/// If unable to get the array segment, return false with a default array segment.
/// </summary>
public bool TryGetArray(out ArraySegment<T> arraySegment)
/// </summary>
public T[] ToArray() => Span.ToArray();
+ /// <summary>
+ /// Determines whether the specified object is equal to the current object.
+ /// Returns true if the object is Memory or ReadOnlyMemory and if both objects point to the same array and have the same length.
+ /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj)
{
_length == other._length;
}
+ /// <summary>
+ /// Serves as the default hash function.
+ /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode()
{
return (T[])(object)text.Substring(start, length).ToCharArray();
}
+#if FEATURE_PORTABLE_SPAN
+ return SpanHelpers.PerTypeValues<T>.EmptyArray;
+#else
return Array.Empty<T>();
+#endif // FEATURE_PORTABLE_SPAN
}
}
}
using System.Runtime.InteropServices;
using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
+#if !FEATURE_PORTABLE_SPAN
using Internal.Runtime.CompilerServices;
+#endif // FEATURE_PORTABLE_SPAN
namespace System
{
/// Defines an implicit conversion of an array to a <see cref="ReadOnlyMemory{T}"/>
/// </summary>
public static implicit operator ReadOnlyMemory<T>(T[] array) => new ReadOnlyMemory<T>(array);
-
+
/// <summary>
/// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="ReadOnlyMemory{T}"/>
/// </summary>
}
else if (typeof(T) == typeof(char) && _object is string s)
{
+#if FEATURE_PORTABLE_SPAN
+ return new ReadOnlySpan<T>(Unsafe.As<Pinnable<T>>(s), MemoryExtensions.StringAdjustment, s.Length).Slice(_index, _length);
+#else
return new ReadOnlySpan<T>(ref Unsafe.As<char, T>(ref s.GetRawStringData()), s.Length).Slice(_index, _length);
+#endif // FEATURE_PORTABLE_SPAN
}
else if (_object != null)
{
else if (typeof(T) == typeof(char) && _object is string s)
{
GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
+#if FEATURE_PORTABLE_SPAN
+ void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
+#endif // FEATURE_PORTABLE_SPAN
memoryHandle = new MemoryHandle(null, pointer, handle);
}
else if (_object is T[] array)
{
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
+#if FEATURE_PORTABLE_SPAN
+ void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
+#endif // FEATURE_PORTABLE_SPAN
memoryHandle = new MemoryHandle(null, pointer, handle);
}
}
{
return _object != null ? CombineHashCodes(_object.GetHashCode(), _index.GetHashCode(), _length.GetHashCode()) : 0;
}
-
+
private static int CombineHashCodes(int left, int right)
{
return ((left << 5) + left) ^ right;
using System.Buffers;
using System.Runtime.CompilerServices;
+#if !FEATURE_PORTABLE_SPAN
using Internal.Runtime.CompilerServices;
+#endif // FEATURE_PORTABLE_SPAN
namespace System.Runtime.InteropServices
{
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.
+ /// </summary>
public static bool TryGetArray<T>(ReadOnlyMemory<T> readOnlyMemory, out ArraySegment<T> arraySegment)
{
object obj = readOnlyMemory.GetObjectStartLength(out int index, out int length);
// This file defines an internal class used to throw exceptions in BCL code.
-// The main purpose is to reduce code size.
-//
+// The main purpose is to reduce code size.
+//
// The old way to throw an exception generates quite a lot IL code and assembly code.
// Following is an example:
// C# source
// IL_0012: newobj instance void System.ArgumentNullException::.ctor(string,string)
// IL_0017: throw
// which is 21bytes in IL.
-//
+//
// So we want to get rid of the ldstr and call to Environment.GetResource in IL.
// In order to do that, I created two enums: ExceptionResource, ExceptionArgument to represent the
-// argument name and resource name in a small integer. The source code will be changed to
+// argument name and resource name in a small integer. The source code will be changed to
// ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key, ExceptionResource.ArgumentNull_Key);
//
// The IL code will be 7 bytes.
// IL_000a: call void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument)
// IL_000f: ldarg.0
//
-// This will also reduce the Jitted code size a lot.
+// This will also reduce the Jitted code size a lot.
+//
+// It is very important we do this for generic classes because we can easily generate the same code
+// multiple times for different instantiation.
//
-// It is very important we do this for generic classes because we can easily generate the same code
-// multiple times for different instantiation.
-//
using System.Collections.Generic;
using System.Runtime.CompilerServices;
throw GetInvalidOperationException(resource);
}
+ internal static void ThrowInvalidOperationException_OutstandingReferences()
+ {
+ ThrowInvalidOperationException(ExceptionResource.Memory_OutstandingReferences);
+ }
+
internal static void ThrowInvalidOperationException(ExceptionResource resource, Exception e)
{
throw new InvalidOperationException(GetResourceString(resource), e);
throw new ObjectDisposedException(null, GetResourceString(resource));
}
+ internal static void ThrowObjectDisposedException_MemoryDisposed()
+ {
+ throw new ObjectDisposedException("OwnedMemory<T>", GetResourceString(ExceptionResource.MemoryDisposed));
+ }
+
internal static void ThrowNotSupportedException()
{
throw new NotSupportedException();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void IfNullAndNullsAreIllegalThenThrow<T>(object value, ExceptionArgument argName)
{
- // Note that default(T) is not equal to null for value types except when T is Nullable<U>.
+ // Note that default(T) is not equal to null for value types except when T is Nullable<U>.
if (!(default(T) == null) && value == null)
ThrowHelper.ThrowArgumentNullException(argName);
}
internal static void ThrowNotSupportedExceptionIfNonNumericType<T>()
{
- if (typeof(T) != typeof(Byte) && typeof(T) != typeof(SByte) &&
- typeof(T) != typeof(Int16) && typeof(T) != typeof(UInt16) &&
- typeof(T) != typeof(Int32) && typeof(T) != typeof(UInt32) &&
+ if (typeof(T) != typeof(Byte) && typeof(T) != typeof(SByte) &&
+ typeof(T) != typeof(Int16) && typeof(T) != typeof(UInt16) &&
+ typeof(T) != typeof(Int32) && typeof(T) != typeof(UInt32) &&
typeof(T) != typeof(Int64) && typeof(T) != typeof(UInt64) &&
typeof(T) != typeof(Single) && typeof(T) != typeof(Double))
{
//
// The convention for this enum is using the argument name as the enum name
- //
+ //
internal enum ExceptionArgument
{
obj,
//
// The convention for this enum is using the resource name as the enum name
- //
+ //
internal enum ExceptionResource
{
Argument_ImplementIComparable,
InvalidOperation_HandleIsNotInitialized,
AsyncMethodBuilder_InstanceNotInitialized,
ArgumentNull_SafeHandle,
+ MemoryDisposed,
}
}