summaryrefslogtreecommitdiff
path: root/src/mscorlib/shared/System
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/shared/System')
-rw-r--r--src/mscorlib/shared/System/CharEnumerator.cs1
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/EventCounter.cs436
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs18
-rw-r--r--src/mscorlib/shared/System/ReadOnlySpan.cs323
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/IsReadOnlyAttribute.cs (renamed from src/mscorlib/shared/System/Runtime/CompilerServices/ReadOnlyAttribute.cs)4
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/RuntimeFeature.cs4
-rw-r--r--src/mscorlib/shared/System/Span.NonGeneric.cs522
-rw-r--r--src/mscorlib/shared/System/Span.cs413
-rw-r--r--src/mscorlib/shared/System/Text/StringBuilder.cs78
-rw-r--r--src/mscorlib/shared/System/Threading/Tasks/TaskExtensions.cs4
10 files changed, 1320 insertions, 483 deletions
diff --git a/src/mscorlib/shared/System/CharEnumerator.cs b/src/mscorlib/shared/System/CharEnumerator.cs
index ea9915a7c4..4dbd5cd587 100644
--- a/src/mscorlib/shared/System/CharEnumerator.cs
+++ b/src/mscorlib/shared/System/CharEnumerator.cs
@@ -17,6 +17,7 @@ using System.Collections.Generic;
namespace System
{
+ [Serializable]
public sealed class CharEnumerator : IEnumerator, IEnumerator<char>, IDisposable, ICloneable
{
private String _str;
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/EventCounter.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/EventCounter.cs
deleted file mode 100644
index b1f946464e..0000000000
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/EventCounter.cs
+++ /dev/null
@@ -1,436 +0,0 @@
-// 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;
-using System.Collections;
-using System.Collections.Generic;
-using System.Threading;
-#if ES_BUILD_PCL
- using System.Threading.Tasks;
-#endif
-
-#if ES_BUILD_STANDALONE
-namespace Microsoft.Diagnostics.Tracing
-#else
-namespace System.Diagnostics.Tracing
-#endif
-{
- /// <summary>
- /// Provides the ability to collect statistics through EventSource
- /// </summary>
- public class EventCounter
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="EventCounter"/> class.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="eventSource">The event source.</param>
- public EventCounter(string name, EventSource eventSource)
- {
- if (name == null)
- {
- throw new ArgumentNullException(nameof(name));
- }
-
- if (eventSource == null)
- {
- throw new ArgumentNullException(nameof(eventSource));
- }
-
- InitializeBuffer();
- _name = name;
- EventCounterGroup.AddEventCounter(eventSource, this);
- }
-
- /// <summary>
- /// Writes the metric.
- /// </summary>
- /// <param name="value">The value.</param>
- public void WriteMetric(float value)
- {
- Enqueue(value);
- }
-
- #region private implementation
-
- private readonly string _name;
-
- #region Buffer Management
-
- // Values buffering
- private const int BufferedSize = 10;
- private const float UnusedBufferSlotValue = float.NegativeInfinity;
- private const int UnsetIndex = -1;
- private volatile float[] _bufferedValues;
- private volatile int _bufferedValuesIndex;
-
- private void InitializeBuffer()
- {
- _bufferedValues = new float[BufferedSize];
- for (int i = 0; i < _bufferedValues.Length; i++)
- {
- _bufferedValues[i] = UnusedBufferSlotValue;
- }
- }
-
- private void Enqueue(float value)
- {
- // It is possible that two threads read the same bufferedValuesIndex, but only one will be able to write the slot, so that is okay.
- int i = _bufferedValuesIndex;
- while (true)
- {
- float result = Interlocked.CompareExchange(ref _bufferedValues[i], value, UnusedBufferSlotValue);
- i++;
- if (_bufferedValues.Length <= i)
- {
- // It is possible that two threads both think the buffer is full, but only one get to actually flush it, the other
- // will eventually enter this code path and potentially calling Flushing on a buffer that is not full, and that's okay too.
- lock (_bufferedValues)
- {
- Flush();
- }
- i = 0;
- }
-
- if (result == UnusedBufferSlotValue)
- {
- // CompareExchange succeeded
- _bufferedValuesIndex = i;
- return;
- }
- }
- }
-
- private void Flush()
- {
- for (int i = 0; i < _bufferedValues.Length; i++)
- {
- var value = Interlocked.Exchange(ref _bufferedValues[i], UnusedBufferSlotValue);
- if (value != UnusedBufferSlotValue)
- {
- OnMetricWritten(value);
- }
- }
-
- _bufferedValuesIndex = 0;
- }
-
- #endregion // Buffer Management
-
- #region Statistics Calculation
-
- // Statistics
- private int _count;
- private float _sum;
- private float _sumSquared;
- private float _min;
- private float _max;
-
- private void OnMetricWritten(float value)
- {
- _sum += value;
- _sumSquared += value * value;
- if (_count == 0 || value > _max)
- {
- _max = value;
- }
-
- if (_count == 0 || value < _min)
- {
- _min = value;
- }
-
- _count++;
- }
-
- internal EventCounterPayload GetEventCounterPayload()
- {
- lock (_bufferedValues)
- {
- Flush();
- EventCounterPayload result = new EventCounterPayload();
- result.Name = _name;
- result.Count = _count;
- result.Mean = _sum / _count;
- result.StandardDerivation = (float)Math.Sqrt(_sumSquared / _count - _sum * _sum / _count / _count);
- result.Min = _min;
- result.Max = _max;
- ResetStatistics();
- return result;
- }
- }
-
- private void ResetStatistics()
- {
- _count = 0;
- _sum = 0;
- _sumSquared = 0;
- _min = 0;
- _max = 0;
- }
-
- #endregion // Statistics Calculation
-
- #endregion // private implementation
- }
-
- #region internal supporting classes
-
- [EventData]
- internal class EventCounterPayload : IEnumerable<KeyValuePair<string, object>>
- {
- public string Name { get; set; }
-
- public float Mean { get; set; }
-
- public float StandardDerivation { get; set; }
-
- public int Count { get; set; }
-
- public float Min { get; set; }
-
- public float Max { get; set; }
-
- public float IntervalSec { get; internal set; }
-
- #region Implementation of the IEnumerable interface
-
- public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
- {
- return ForEnumeration.GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return ForEnumeration.GetEnumerator();
- }
-
- private IEnumerable<KeyValuePair<string, object>> ForEnumeration
- {
- get
- {
- yield return new KeyValuePair<string, object>("Name", Name);
- yield return new KeyValuePair<string, object>("Mean", Mean);
- yield return new KeyValuePair<string, object>("StandardDerivation", StandardDerivation);
- yield return new KeyValuePair<string, object>("Count", Count);
- yield return new KeyValuePair<string, object>("Min", Min);
- yield return new KeyValuePair<string, object>("Max", Max);
- }
- }
-
- #endregion // Implementation of the IEnumerable interface
- }
-
- internal class EventCounterGroup : IDisposable
- {
- private readonly EventSource _eventSource;
- private readonly int _eventSourceIndex;
- private readonly List<EventCounter> _eventCounters;
-
- internal EventCounterGroup(EventSource eventSource, int eventSourceIndex)
- {
- _eventSource = eventSource;
- _eventSourceIndex = eventSourceIndex;
- _eventCounters = new List<EventCounter>();
- RegisterCommandCallback();
- }
-
- private void Add(EventCounter eventCounter)
- {
- _eventCounters.Add(eventCounter);
- }
-
- #region EventSource Command Processing
-
- private void RegisterCommandCallback()
- {
- _eventSource.EventCommandExecuted += OnEventSourceCommand;
- }
-
- private void OnEventSourceCommand(object sender, EventCommandEventArgs e)
- {
- if (e.Command == EventCommand.Enable || e.Command == EventCommand.Update)
- {
- string valueStr;
- float value;
- if (e.Arguments.TryGetValue("EventCounterIntervalSec", out valueStr) && float.TryParse(valueStr, out value))
- {
- EnableTimer(value);
- }
- }
- }
-
- #endregion // EventSource Command Processing
-
- #region Global EventCounterGroup Array management
-
- private static EventCounterGroup[] s_eventCounterGroups;
-
- internal static void AddEventCounter(EventSource eventSource, EventCounter eventCounter)
- {
- int eventSourceIndex = EventListener.EventSourceIndex(eventSource);
-
- EventCounterGroup.EnsureEventSourceIndexAvailable(eventSourceIndex);
- EventCounterGroup eventCounterGroup = GetEventCounterGroup(eventSource);
- eventCounterGroup.Add(eventCounter);
- }
-
- private static void EnsureEventSourceIndexAvailable(int eventSourceIndex)
- {
- if (EventCounterGroup.s_eventCounterGroups == null)
- {
- EventCounterGroup.s_eventCounterGroups = new EventCounterGroup[eventSourceIndex + 1];
- }
- else if (eventSourceIndex >= EventCounterGroup.s_eventCounterGroups.Length)
- {
- EventCounterGroup[] newEventCounterGroups = new EventCounterGroup[eventSourceIndex + 1];
- Array.Copy(EventCounterGroup.s_eventCounterGroups, 0, newEventCounterGroups, 0, EventCounterGroup.s_eventCounterGroups.Length);
- EventCounterGroup.s_eventCounterGroups = newEventCounterGroups;
- }
- }
-
- private static EventCounterGroup GetEventCounterGroup(EventSource eventSource)
- {
- int eventSourceIndex = EventListener.EventSourceIndex(eventSource);
- EventCounterGroup result = EventCounterGroup.s_eventCounterGroups[eventSourceIndex];
- if (result == null)
- {
- result = new EventCounterGroup(eventSource, eventSourceIndex);
- EventCounterGroup.s_eventCounterGroups[eventSourceIndex] = result;
- }
-
- return result;
- }
-
- #endregion // Global EventCounterGroup Array management
-
- #region Timer Processing
-
- private DateTime _timeStampSinceCollectionStarted;
- private int _pollingIntervalInMilliseconds;
- private Timer _pollingTimer;
-
- private void EnableTimer(float pollingIntervalInSeconds)
- {
- if (pollingIntervalInSeconds == 0)
- {
- if (_pollingTimer != null)
- {
- _pollingTimer.Dispose();
- _pollingTimer = null;
- }
-
- _pollingIntervalInMilliseconds = 0;
- }
- else if (_pollingIntervalInMilliseconds == 0 || pollingIntervalInSeconds < _pollingIntervalInMilliseconds)
- {
- _pollingIntervalInMilliseconds = (int)(pollingIntervalInSeconds * 1000);
- if (_pollingTimer != null)
- {
- _pollingTimer.Dispose();
- _pollingTimer = null;
- }
-
- _timeStampSinceCollectionStarted = DateTime.Now;
- _pollingTimer = new Timer(OnTimer, null, _pollingIntervalInMilliseconds, _pollingIntervalInMilliseconds);
- }
- }
-
- private void OnTimer(object state)
- {
- if (_eventSource.IsEnabled())
- {
- DateTime now = DateTime.Now;
- TimeSpan elapsed = now - _timeStampSinceCollectionStarted;
- lock (_pollingTimer)
- {
- foreach (var eventCounter in _eventCounters)
- {
- EventCounterPayload payload = eventCounter.GetEventCounterPayload();
- payload.IntervalSec = (float)elapsed.TotalSeconds;
- _eventSource.Write("EventCounters", new EventSourceOptions() { Level = EventLevel.LogAlways }, new { Payload = payload });
- }
-
-
- _timeStampSinceCollectionStarted = now;
- }
- }
- else
- {
- _pollingTimer.Dispose();
- _pollingTimer = null;
- EventCounterGroup.s_eventCounterGroups[_eventSourceIndex] = null;
- }
- }
-
- #region PCL timer hack
-
-#if ES_BUILD_PCL
- internal delegate void TimerCallback(object state);
-
- internal sealed class Timer : CancellationTokenSource, IDisposable
- {
- private int _period;
- private TimerCallback _callback;
- private object _state;
-
- internal Timer(TimerCallback callback, object state, int dueTime, int period)
- {
- _callback = callback;
- _state = state;
- _period = period;
- Schedule(dueTime);
- }
-
- private void Schedule(int dueTime)
- {
- Task.Delay(dueTime, Token).ContinueWith(OnTimer, null, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);
- }
-
- private void OnTimer(Task t, object s)
- {
- Schedule(_period);
- _callback(_state);
- }
-
- public new void Dispose() { base.Cancel(); }
- }
-#endif
- #endregion // PCL timer hack
-
- #endregion // Timer Processing
-
- #region Implementation of the IDisposable interface
-
- private bool _disposed = false;
-
- public void Dispose()
- {
- Dispose(true);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (_disposed)
- {
- return;
- }
-
- if (disposing)
- {
- if (_pollingTimer != null)
- {
- _pollingTimer.Dispose();
- _pollingTimer = null;
- }
- }
-
- _disposed = true;
- }
-
- #endregion // Implementation of the IDisposable interface
- }
-
- #endregion // internal supporting classes
-}
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs
index 57d550dc8c..e18574c1b4 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs
@@ -555,21 +555,21 @@ namespace System.Diagnostics.Tracing
{
#if (!ES_BUILD_PCL && !ES_BUILD_PN && !FEATURE_PAL)
string regKey = @"\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + m_providerId + "}";
- if (Marshal.SizeOf(typeof(IntPtr)) == 8)
- regKey = @"Software" + @"\Wow6432Node" + regKey;
+ if (System.Runtime.InteropServices.Marshal.SizeOf(typeof(IntPtr)) == 8)
+ regKey = @"HKEY_LOCAL_MACHINE\Software" + @"\Wow6432Node" + regKey;
else
- regKey = @"Software" + regKey;
+ regKey = @"HKEY_LOCAL_MACHINE\Software" + regKey;
string valueName = "ControllerData_Session_" + etwSessionId.ToString(CultureInfo.InvariantCulture);
- using (RegistryKey key = Registry.LocalMachine.OpenSubKey(regKey, writable: false))
- {
- data = key.GetValue(valueName) as byte[];
- }
-
+ // we need to assert this permission for partial trust scenarios
+#if !CORECLR
+ (new RegistryPermission(RegistryPermissionAccess.Read, regKey)).Assert();
+#endif
+ data = Microsoft.Win32.Registry.GetValue(regKey, valueName, null) as byte[];
if (data != null)
{
- // We only used the persisted data from the registry for updates.
+ // We only used the persisted data from the registry for updates.
command = ControllerCommand.Update;
return true;
}
diff --git a/src/mscorlib/shared/System/ReadOnlySpan.cs b/src/mscorlib/shared/System/ReadOnlySpan.cs
new file mode 100644
index 0000000000..8ec431f6fb
--- /dev/null
+++ b/src/mscorlib/shared/System/ReadOnlySpan.cs
@@ -0,0 +1,323 @@
+// 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.Diagnostics;
+using System.Runtime.CompilerServices;
+using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
+using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
+
+#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
+
+namespace System
+{
+ /// <summary>
+ /// ReadOnlySpan represents a contiguous region of arbitrary memory. Unlike arrays, it can point to either managed
+ /// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
+ /// </summary>
+ public struct ReadOnlySpan<T>
+ {
+ /// <summary>A byref or a native ptr.</summary>
+ private readonly ByReference<T> _pointer;
+ /// <summary>The number of elements this ReadOnlySpan contains.</summary>
+#if PROJECTN
+ [Bound]
+#endif
+ private readonly int _length;
+
+ /// <summary>
+ /// Creates a new read-only span over the entirety of the target array.
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
+ /// reference (Nothing in Visual Basic).</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan(T[] array)
+ {
+ if (array == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+
+ _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()));
+ _length = array.Length;
+ }
+
+ /// <summary>
+ /// Creates a new read-only span over the portion of the target array beginning
+ /// at 'start' index and covering the remainder of the array.
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <param name="start">The index at which to begin the read-only span.</param>
+ /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
+ /// reference (Nothing in Visual Basic).</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> is not in the range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan(T[] array, int start)
+ {
+ if (array == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ if ((uint)start > (uint)array.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
+ _length = array.Length - start;
+ }
+
+ /// <summary>
+ /// Creates a new read-only span 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 read-only span.</param>
+ /// <param name="length">The number of items in the read-only span.</param>
+ /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
+ /// reference (Nothing in Visual Basic).</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan(T[] array, int start, int length)
+ {
+ if (array == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
+ _length = length;
+ }
+
+ /// <summary>
+ /// Creates a new read-only span over the target unmanaged buffer. Clearly this
+ /// is quite dangerous, because we are creating arbitrarily typed T's
+ /// out of a void*-typed block of memory. And the length is not checked.
+ /// But if this creation is correct, then all subsequent uses are correct.
+ /// </summary>
+ /// <param name="pointer">An unmanaged pointer to memory.</param>
+ /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> is reference type or contains pointers and hence cannot be stored in unmanaged memory.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="length"/> is negative.
+ /// </exception>
+ [CLSCompliant(false)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe ReadOnlySpan(void* pointer, int length)
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+ if (length < 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
+ _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)]
+ 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)
+ {
+ Debug.Assert(length >= 0);
+
+ _pointer = new ByReference<T>(ref ptr);
+ _length = length;
+ }
+
+ /// <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>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ref T DangerousGetPinnableReference()
+ {
+ return ref _pointer.Value;
+ }
+
+ /// <summary>
+ /// The number of items in the read-only span.
+ /// </summary>
+ public int Length => _length;
+
+ /// <summary>
+ /// Returns true if Length is 0.
+ /// </summary>
+ public bool IsEmpty => _length == 0;
+
+ /// <summary>
+ /// Returns the specified element of the read-only span.
+ /// </summary>
+ /// <param name="index"></param>
+ /// <returns></returns>
+ /// <exception cref="System.IndexOutOfRangeException">
+ /// Thrown when index less than 0 or index greater than or equal to Length
+ /// </exception>
+ public T this[int index]
+ {
+#if PROJECTN
+ [BoundsChecking]
+ get
+ {
+ return Unsafe.Add(ref _pointer.Value, index);
+ }
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ if ((uint)index >= (uint)_length)
+ ThrowHelper.ThrowIndexOutOfRangeException();
+ return Unsafe.Add(ref _pointer.Value, index);
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Copies the contents of this read-only span into destination span. If the source
+ /// and destinations overlap, this method behaves as if the original values in
+ /// a temporary location before the destination is overwritten.
+ ///
+ /// <param name="destination">The span to copy items into.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when the destination Span is shorter than the source Span.
+ /// </exception>
+ /// </summary>
+ public void CopyTo(Span<T> destination)
+ {
+ if (!TryCopyTo(destination))
+ ThrowHelper.ThrowArgumentException_DestinationTooShort();
+ }
+
+ /// Copies the contents of this read-only span into destination span. If the source
+ /// and destinations overlap, this method behaves as if the original values in
+ /// a temporary location before the destination is overwritten.
+ /// </summary>
+ /// <returns>If the destination span is shorter than the source span, this method
+ /// return false and no data is written to the destination.</returns>
+ /// <param name="destination">The span to copy items into.</param>
+ public bool TryCopyTo(Span<T> destination)
+ {
+ if ((uint)_length > (uint)destination.Length)
+ return false;
+
+ Span.CopyTo<T>(ref destination.DangerousGetPinnableReference(), ref _pointer.Value, _length);
+ return true;
+ }
+
+ /// <summary>
+ /// Returns true if left and right point at the same memory and have the same length. Note that
+ /// this does *not* check to see if the *contents* are equal.
+ /// </summary>
+ public static bool operator ==(ReadOnlySpan<T> left, ReadOnlySpan<T> right)
+ {
+ return left._length == right._length && Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
+ }
+
+ /// <summary>
+ /// Returns false if left and right point at the same memory and have the same length. Note that
+ /// this does *not* check to see if the *contents* are equal.
+ /// </summary>
+ public static bool operator !=(ReadOnlySpan<T> left, ReadOnlySpan<T> right) => !(left == right);
+
+ /// <summary>
+ /// This method is not supported as spans cannot be boxed. To compare two spans, use operator==.
+ /// <exception cref="System.NotSupportedException">
+ /// Always thrown by this method.
+ /// </exception>
+ /// </summary>
+ [Obsolete("Equals() on Span will always throw an exception. Use == instead.")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool Equals(object obj)
+ {
+ throw new NotSupportedException(SR.NotSupported_CannotCallEqualsOnSpan);
+ }
+
+ /// <summary>
+ /// This method is not supported as spans cannot be boxed.
+ /// <exception cref="System.NotSupportedException">
+ /// Always thrown by this method.
+ /// </exception>
+ /// </summary>
+ [Obsolete("GetHashCode() on Span will always throw an exception.")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override int GetHashCode()
+ {
+ throw new NotSupportedException(SR.NotSupported_CannotCallGetHashCodeOnSpan);
+ }
+
+ /// <summary>
+ /// Defines an implicit conversion of an array to a <see cref="ReadOnlySpan{T}"/>
+ /// </summary>
+ public static implicit operator ReadOnlySpan<T>(T[] array) => new ReadOnlySpan<T>(array);
+
+ /// <summary>
+ /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="ReadOnlySpan{T}"/>
+ /// </summary>
+ public static implicit operator ReadOnlySpan<T>(ArraySegment<T> arraySegment) => new ReadOnlySpan<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
+
+ /// <summary>
+ /// Forms a slice out of the given read-only span, beginning at 'start'.
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan<T> Slice(int start)
+ {
+ if ((uint)start > (uint)_length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, start), _length - start);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given read-only span, beginning at 'start', of given length
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="length">The desired length for the slice (exclusive).</param>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan<T> Slice(int start, int length)
+ {
+ if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
+ }
+
+ /// <summary>
+ /// Copies the contents of this read-only span into a new array. This heap
+ /// allocates, so should generally be avoided, however it is sometimes
+ /// necessary to bridge the gap with APIs written in terms of arrays.
+ /// </summary>
+ public T[] ToArray()
+ {
+ if (_length == 0)
+ return Array.Empty<T>();
+
+ var destination = new T[_length];
+ Span.CopyTo<T>(ref Unsafe.As<byte, T>(ref destination.GetRawSzArrayData()), ref _pointer.Value, _length);
+ return destination;
+ }
+
+ /// <summary>
+ /// Returns a 0-length read-only span whose base is the null pointer.
+ /// </summary>
+ public static ReadOnlySpan<T> Empty => default(ReadOnlySpan<T>);
+ }
+}
diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/ReadOnlyAttribute.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/IsReadOnlyAttribute.cs
index aad7310412..657df43957 100644
--- a/src/mscorlib/shared/System/Runtime/CompilerServices/ReadOnlyAttribute.cs
+++ b/src/mscorlib/shared/System/Runtime/CompilerServices/IsReadOnlyAttribute.cs
@@ -12,9 +12,9 @@ namespace System.Runtime.CompilerServices
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[AttributeUsage(AttributeTargets.All, Inherited = false)]
- public sealed class ReadOnlyAttribute : Attribute
+ public sealed class IsReadOnlyAttribute : Attribute
{
- public ReadOnlyAttribute()
+ public IsReadOnlyAttribute()
{
}
}
diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/RuntimeFeature.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/RuntimeFeature.cs
index b93c435439..110a55fd2c 100644
--- a/src/mscorlib/shared/System/Runtime/CompilerServices/RuntimeFeature.cs
+++ b/src/mscorlib/shared/System/Runtime/CompilerServices/RuntimeFeature.cs
@@ -12,7 +12,9 @@ namespace System.Runtime.CompilerServices
public static bool IsSupported(string feature)
{
// No features are supported for now.
- // These features should be added as public static readonly string fields in the same class.
+ // These features should be added as public const string fields in the same class.
+ // Example: public const string FeatureName = nameof(FeatureName);
+
return false;
}
}
diff --git a/src/mscorlib/shared/System/Span.NonGeneric.cs b/src/mscorlib/shared/System/Span.NonGeneric.cs
new file mode 100644
index 0000000000..4cdba2181a
--- /dev/null
+++ b/src/mscorlib/shared/System/Span.NonGeneric.cs
@@ -0,0 +1,522 @@
+// 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.Diagnostics;
+using System.Runtime;
+using System.Runtime.CompilerServices;
+
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif
+
+namespace System
+{
+ /// <summary>
+ /// Extension methods and non-generic helpers for Span and ReadOnlySpan
+ /// </summary>
+ public static class Span
+ {
+ /// <summary>
+ /// Casts a Span of one primitive type <typeparamref name="T"/> to Span of bytes.
+ /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <param name="source">The source slice, of type <typeparamref name="T"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> contains pointers.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span<byte> AsBytes<T>(this Span<T> source)
+ where T : struct
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+
+ return new Span<byte>(
+ ref Unsafe.As<T, byte>(ref source.DangerousGetPinnableReference()),
+ checked(source.Length * Unsafe.SizeOf<T>()));
+ }
+
+ /// <summary>
+ /// Casts a ReadOnlySpan of one primitive type <typeparamref name="T"/> to ReadOnlySpan of bytes.
+ /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <param name="source">The source slice, of type <typeparamref name="T"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> contains pointers.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<byte> AsBytes<T>(this ReadOnlySpan<T> source)
+ where T : struct
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+
+ return new ReadOnlySpan<byte>(
+ ref Unsafe.As<T, byte>(ref source.DangerousGetPinnableReference()),
+ checked(source.Length * Unsafe.SizeOf<T>()));
+ }
+
+ /// <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 source.DangerousGetPinnableReference()),
+ 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>
+ /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null
+ /// reference (Nothing in Visual Basic).</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<char> AsSpan(this string text)
+ {
+ if (text == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
+
+ return new ReadOnlySpan<char>(ref text.GetRawStringData(), text.Length);
+ }
+
+ internal static unsafe void CopyTo<T>(ref T destination, ref T source, int elementsCount)
+ {
+ if (Unsafe.AreSame(ref destination, ref source))
+ return;
+
+ if (elementsCount <= 1)
+ {
+ if (elementsCount == 1)
+ {
+ destination = source;
+ }
+ return;
+ }
+
+ nuint byteCount = (nuint)elementsCount * (nuint)Unsafe.SizeOf<T>();
+ if (!RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ {
+ fixed (byte* pDestination = &Unsafe.As<T, byte>(ref destination))
+ {
+ fixed (byte* pSource = &Unsafe.As<T, byte>(ref source))
+ {
+ Buffer.Memmove(pDestination, pSource, byteCount);
+ }
+ }
+ }
+ else
+ {
+ RuntimeImports.RhBulkMoveWithWriteBarrier(
+ ref Unsafe.As<T, byte>(ref destination),
+ ref Unsafe.As<T, byte>(ref source),
+ byteCount);
+ }
+ }
+
+ internal static unsafe void ClearWithoutReferences(ref byte b, nuint byteLength)
+ {
+ if (byteLength == 0)
+ return;
+
+#if AMD64 && CORECLR
+ if (byteLength > 4096) goto PInvoke;
+ Unsafe.InitBlockUnaligned(ref b, 0, (uint)byteLength);
+ return;
+#else
+ // TODO: Optimize other platforms to be on par with AMD64 CoreCLR
+ // Note: It's important that this switch handles lengths at least up to 22.
+ // See notes below near the main loop for why.
+
+ // The switch will be very fast since it can be implemented using a jump
+ // table in assembly. See http://stackoverflow.com/a/449297/4077294 for more info.
+
+ switch (byteLength)
+ {
+ case 1:
+ b = 0;
+ return;
+ case 2:
+ Unsafe.As<byte, short>(ref b) = 0;
+ return;
+ case 3:
+ Unsafe.As<byte, short>(ref b) = 0;
+ Unsafe.Add<byte>(ref b, 2) = 0;
+ return;
+ case 4:
+ Unsafe.As<byte, int>(ref b) = 0;
+ return;
+ case 5:
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.Add<byte>(ref b, 4) = 0;
+ return;
+ case 6:
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ return;
+ case 7:
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.Add<byte>(ref b, 6) = 0;
+ return;
+ case 8:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ return;
+ case 9:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.Add<byte>(ref b, 8) = 0;
+ return;
+ case 10:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ return;
+ case 11:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.Add<byte>(ref b, 10) = 0;
+ return;
+ case 12:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ return;
+ case 13:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.Add<byte>(ref b, 12) = 0;
+ return;
+ case 14:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+ return;
+ case 15:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+ Unsafe.Add<byte>(ref b, 14) = 0;
+ return;
+ case 16:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ return;
+ case 17:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ Unsafe.Add<byte>(ref b, 16) = 0;
+ return;
+ case 18:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
+ return;
+ case 19:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
+ Unsafe.Add<byte>(ref b, 18) = 0;
+ return;
+ case 20:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
+ return;
+ case 21:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
+ Unsafe.Add<byte>(ref b, 20) = 0;
+ return;
+ case 22:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 20)) = 0;
+ return;
+ }
+
+ // P/Invoke into the native version for large lengths
+ if (byteLength >= 512) goto PInvoke;
+
+ nuint i = 0; // byte offset at which we're copying
+
+ if ((Unsafe.As<byte, int>(ref b) & 3) != 0)
+ {
+ if ((Unsafe.As<byte, int>(ref b) & 1) != 0)
+ {
+ Unsafe.AddByteOffset<byte>(ref b, i) = 0;
+ i += 1;
+ if ((Unsafe.As<byte, int>(ref b) & 2) != 0)
+ goto IntAligned;
+ }
+ Unsafe.As<byte, short>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ i += 2;
+ }
+
+ IntAligned:
+
+ // On 64-bit IntPtr.Size == 8, so we want to advance to the next 8-aligned address. If
+ // (int)b % 8 is 0, 5, 6, or 7, we will already have advanced by 0, 3, 2, or 1
+ // bytes to the next aligned address (respectively), so do nothing. On the other hand,
+ // if it is 1, 2, 3, or 4 we will want to copy-and-advance another 4 bytes until
+ // we're aligned.
+ // The thing 1, 2, 3, and 4 have in common that the others don't is that if you
+ // subtract one from them, their 3rd lsb will not be set. Hence, the below check.
+
+ if (((Unsafe.As<byte, int>(ref b) - 1) & 4) == 0)
+ {
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ i += 4;
+ }
+
+ nuint end = byteLength - 16;
+ byteLength -= i; // lower 4 bits of byteLength represent how many bytes are left *after* the unrolled loop
+
+ // We know due to the above switch-case that this loop will always run 1 iteration; max
+ // bytes we clear before checking is 23 (7 to align the pointers, 16 for 1 iteration) so
+ // the switch handles lengths 0-22.
+ Debug.Assert(end >= 7 && i <= end);
+
+ // This is separated out into a different variable, so the i + 16 addition can be
+ // performed at the start of the pipeline and the loop condition does not have
+ // a dependency on the writes.
+ nuint counter;
+
+ do
+ {
+ counter = i + 16;
+
+ // This loop looks very costly since there appear to be a bunch of temporary values
+ // being created with the adds, but the jit (for x86 anyways) will convert each of
+ // these to use memory addressing operands.
+
+ // So the only cost is a bit of code size, which is made up for by the fact that
+ // we save on writes to b.
+
+#if BIT64
+ Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i + 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 12)) = 0;
+#endif
+
+ i = counter;
+
+ // See notes above for why this wasn't used instead
+ // i += 16;
+ }
+ while (counter <= end);
+
+ if ((byteLength & 8) != 0)
+ {
+#if BIT64
+ Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+#else
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 4)) = 0;
+#endif
+ i += 8;
+ }
+ if ((byteLength & 4) != 0)
+ {
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ i += 4;
+ }
+ if ((byteLength & 2) != 0)
+ {
+ Unsafe.As<byte, short>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ i += 2;
+ }
+ if ((byteLength & 1) != 0)
+ {
+ Unsafe.AddByteOffset<byte>(ref b, i) = 0;
+ // We're not using i after this, so not needed
+ // i += 1;
+ }
+
+ return;
+#endif
+
+ PInvoke:
+ RuntimeImports.RhZeroMemory(ref b, byteLength);
+ }
+
+ internal static unsafe void ClearWithReferences(ref IntPtr ip, nuint pointerSizeLength)
+ {
+ if (pointerSizeLength == 0)
+ return;
+
+ // TODO: Perhaps do switch casing to improve small size perf
+
+ nuint i = 0;
+ nuint n = 0;
+ while ((n = i + 8) <= (pointerSizeLength))
+ {
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 2) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 3) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 4) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 5) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 6) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 7) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ i = n;
+ }
+ if ((n = i + 4) <= (pointerSizeLength))
+ {
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 2) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 3) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ i = n;
+ }
+ if ((n = i + 2) <= (pointerSizeLength))
+ {
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ i = n;
+ }
+ if ((i + 1) <= (pointerSizeLength))
+ {
+ Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr);
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/shared/System/Span.cs b/src/mscorlib/shared/System/Span.cs
new file mode 100644
index 0000000000..82ea35f670
--- /dev/null
+++ b/src/mscorlib/shared/System/Span.cs
@@ -0,0 +1,413 @@
+// 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.Diagnostics;
+using System.Runtime;
+using System.Runtime.CompilerServices;
+using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
+using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
+
+#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
+
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif
+
+namespace System
+{
+ /// <summary>
+ /// Span represents a contiguous region of arbitrary memory. Unlike arrays, it can point to either managed
+ /// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
+ /// </summary>
+ public struct Span<T>
+ {
+ /// <summary>A byref or a native ptr.</summary>
+ private readonly ByReference<T> _pointer;
+ /// <summary>The number of elements this Span contains.</summary>
+#if PROJECTN
+ [Bound]
+#endif
+ private readonly int _length;
+
+ /// <summary>
+ /// Creates a new span over the entirety of the target array.
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
+ /// reference (Nothing in Visual Basic).</exception>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span(T[] array)
+ {
+ if (array == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ if (default(T) == null && array.GetType() != typeof(T[]))
+ ThrowHelper.ThrowArrayTypeMismatchException();
+
+ _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()));
+ _length = array.Length;
+ }
+
+ /// <summary>
+ /// Creates a new span over the portion of the target array beginning
+ /// at 'start' index and covering the remainder of the array.
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <param name="start">The index at which to begin the span.</param>
+ /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
+ /// reference (Nothing in Visual Basic).</exception>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> is not in the range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span(T[] array, int start)
+ {
+ if (array == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ if (default(T) == null && array.GetType() != typeof(T[]))
+ ThrowHelper.ThrowArrayTypeMismatchException();
+ if ((uint)start > (uint)array.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
+ _length = array.Length - start;
+ }
+
+ /// <summary>
+ /// Creates a new span 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 span.</param>
+ /// <param name="length">The number of items in the span.</param>
+ /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
+ /// reference (Nothing in Visual Basic).</exception>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span(T[] array, int start, int length)
+ {
+ if (array == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ if (default(T) == null && array.GetType() != typeof(T[]))
+ ThrowHelper.ThrowArrayTypeMismatchException();
+ if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
+ _length = length;
+ }
+
+ /// <summary>
+ /// Creates a new span over the target unmanaged buffer. Clearly this
+ /// is quite dangerous, because we are creating arbitrarily typed T's
+ /// out of a void*-typed block of memory. And the length is not checked.
+ /// But if this creation is correct, then all subsequent uses are correct.
+ /// </summary>
+ /// <param name="pointer">An unmanaged pointer to memory.</param>
+ /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> is reference type or contains pointers and hence cannot be stored in unmanaged memory.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="length"/> is negative.
+ /// </exception>
+ [CLSCompliant(false)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe Span(void* pointer, int length)
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+ if (length < 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
+ _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)]
+ 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)
+ {
+ Debug.Assert(length >= 0);
+
+ _pointer = new ByReference<T>(ref ptr);
+ _length = length;
+ }
+
+ /// <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 ref T DangerousGetPinnableReference()
+ {
+ return ref _pointer.Value;
+ }
+
+ /// <summary>
+ /// The number of items in the span.
+ /// </summary>
+ public int Length => _length;
+
+ /// <summary>
+ /// Returns true if Length is 0.
+ /// </summary>
+ public bool IsEmpty => _length == 0;
+
+ /// <summary>
+ /// Returns a reference to specified element of the Span.
+ /// </summary>
+ /// <param name="index"></param>
+ /// <returns></returns>
+ /// <exception cref="System.IndexOutOfRangeException">
+ /// Thrown when index less than 0 or index greater than or equal to Length
+ /// </exception>
+ public ref T this[int index]
+ {
+#if PROJECTN
+ [BoundsChecking]
+ get
+ {
+ return ref Unsafe.Add(ref _pointer.Value, index);
+ }
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ if ((uint)index >= (uint)_length)
+ ThrowHelper.ThrowIndexOutOfRangeException();
+ return ref Unsafe.Add(ref _pointer.Value, index);
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Clears the contents of this span.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Clear()
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ {
+ Span.ClearWithReferences(ref Unsafe.As<T, IntPtr>(ref _pointer.Value), (nuint)_length * (nuint)(Unsafe.SizeOf<T>() / sizeof(nuint)));
+ }
+ else
+ {
+ Span.ClearWithoutReferences(ref Unsafe.As<T, byte>(ref _pointer.Value), (nuint)_length * (nuint)Unsafe.SizeOf<T>());
+ }
+ }
+
+ /// <summary>
+ /// Fills the contents of this span with the given value.
+ /// </summary>
+ public void Fill(T value)
+ {
+ if (Unsafe.SizeOf<T>() == 1)
+ {
+ uint length = (uint)_length;
+ if (length == 0)
+ return;
+
+ T tmp = value; // Avoid taking address of the "value" argument. It would regress performance of the loop below.
+ Unsafe.InitBlockUnaligned(ref Unsafe.As<T, byte>(ref _pointer.Value), Unsafe.As<T, byte>(ref tmp), length);
+ }
+ else
+ {
+ // Do all math as nuint to avoid unnecessary 64->32->64 bit integer truncations
+ nuint length = (uint)_length;
+ if (length == 0)
+ return;
+
+ ref T r = ref DangerousGetPinnableReference();
+
+ // TODO: Create block fill for value types of power of two sizes e.g. 2,4,8,16
+
+ nuint elementSize = (uint)Unsafe.SizeOf<T>();
+ nuint i = 0;
+ for (; i < (length & ~(nuint)7); i += 8)
+ {
+ Unsafe.AddByteOffset<T>(ref r, (i + 0) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 1) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 2) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 3) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 4) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 5) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 6) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 7) * elementSize) = value;
+ }
+ if (i < (length & ~(nuint)3))
+ {
+ Unsafe.AddByteOffset<T>(ref r, (i + 0) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 1) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 2) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 3) * elementSize) = value;
+ i += 4;
+ }
+ for (; i < length; i++)
+ {
+ Unsafe.AddByteOffset<T>(ref r, i * elementSize) = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Copies the contents of this span into destination span. If the source
+ /// and destinations overlap, this method behaves as if the original values in
+ /// a temporary location before the destination is overwritten.
+ /// </summary>
+ /// <param name="destination">The span to copy items into.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when the destination Span is shorter than the source Span.
+ /// </exception>
+ public void CopyTo(Span<T> destination)
+ {
+ if (!TryCopyTo(destination))
+ ThrowHelper.ThrowArgumentException_DestinationTooShort();
+ }
+
+ /// <summary>
+ /// Copies the contents of this span into destination span. If the source
+ /// and destinations overlap, this method behaves as if the original values in
+ /// a temporary location before the destination is overwritten.
+ /// </summary>
+ /// <param name="destination">The span to copy items into.</param>
+ /// <returns>If the destination span is shorter than the source span, this method
+ /// return false and no data is written to the destination.</returns>
+ public bool TryCopyTo(Span<T> destination)
+ {
+ if ((uint)_length > (uint)destination.Length)
+ return false;
+
+ Span.CopyTo<T>(ref destination._pointer.Value, ref _pointer.Value, _length);
+ return true;
+ }
+
+ /// <summary>
+ /// Returns true if left and right point at the same memory and have the same length. Note that
+ /// this does *not* check to see if the *contents* are equal.
+ /// </summary>
+ public static bool operator ==(Span<T> left, Span<T> right)
+ {
+ return left._length == right._length && Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
+ }
+
+ /// <summary>
+ /// Returns false if left and right point at the same memory and have the same length. Note that
+ /// this does *not* check to see if the *contents* are equal.
+ /// </summary>
+ public static bool operator !=(Span<T> left, Span<T> right) => !(left == right);
+
+ /// <summary>
+ /// This method is not supported as spans cannot be boxed. To compare two spans, use operator==.
+ /// <exception cref="System.NotSupportedException">
+ /// Always thrown by this method.
+ /// </exception>
+ /// </summary>
+ [Obsolete("Equals() on Span will always throw an exception. Use == instead.")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool Equals(object obj)
+ {
+ throw new NotSupportedException(SR.NotSupported_CannotCallEqualsOnSpan);
+ }
+
+ /// <summary>
+ /// This method is not supported as spans cannot be boxed.
+ /// <exception cref="System.NotSupportedException">
+ /// Always thrown by this method.
+ /// </exception>
+ /// </summary>
+ [Obsolete("GetHashCode() on Span will always throw an exception.")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override int GetHashCode()
+ {
+ throw new NotSupportedException(SR.NotSupported_CannotCallGetHashCodeOnSpan);
+ }
+
+ /// <summary>
+ /// Defines an implicit conversion of an array to a <see cref="Span{T}"/>
+ /// </summary>
+ public static implicit operator Span<T>(T[] array) => new Span<T>(array);
+
+ /// <summary>
+ /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="Span{T}"/>
+ /// </summary>
+ public static implicit operator Span<T>(ArraySegment<T> arraySegment) => new Span<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
+
+ /// <summary>
+ /// Defines an implicit conversion of a <see cref="Span{T}"/> to a <see cref="ReadOnlySpan{T}"/>
+ /// </summary>
+ public static implicit operator ReadOnlySpan<T>(Span<T> span) => new ReadOnlySpan<T>(ref span._pointer.Value, span._length);
+
+ /// <summary>
+ /// Forms a slice out of the given span, beginning at 'start'.
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span<T> Slice(int start)
+ {
+ if ((uint)start > (uint)_length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new Span<T>(ref Unsafe.Add(ref _pointer.Value, start), _length - start);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given span, beginning at 'start', of given length
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="length">The desired length for the slice (exclusive).</param>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span<T> Slice(int start, int length)
+ {
+ if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new Span<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
+ }
+
+ /// <summary>
+ /// Copies the contents of this span into a new array. This heap
+ /// allocates, so should generally be avoided, however it is sometimes
+ /// necessary to bridge the gap with APIs written in terms of arrays.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public T[] ToArray()
+ {
+ if (_length == 0)
+ return Array.Empty<T>();
+
+ var destination = new T[_length];
+ Span.CopyTo<T>(ref Unsafe.As<byte, T>(ref destination.GetRawSzArrayData()), ref _pointer.Value, _length);
+ return destination;
+ }
+
+ // <summary>
+ /// Returns an empty <see cref="Span{T}"/>
+ /// </summary>
+ public static Span<T> Empty => default(Span<T>);
+ }
+}
diff --git a/src/mscorlib/shared/System/Text/StringBuilder.cs b/src/mscorlib/shared/System/Text/StringBuilder.cs
index df1a889823..3a06114bff 100644
--- a/src/mscorlib/shared/System/Text/StringBuilder.cs
+++ b/src/mscorlib/shared/System/Text/StringBuilder.cs
@@ -1081,67 +1081,56 @@ namespace System.Text
return this;
}
- // Append joined values with a separator between each value.
- public unsafe StringBuilder AppendJoin<T>(char separator, params T[] values)
- {
- // Defer argument validation to the internal function
- return AppendJoinCore(&separator, 1, values);
- }
+
+ #region AppendJoin
- public unsafe StringBuilder AppendJoin<T>(string separator, params T[] values)
+ public unsafe StringBuilder AppendJoin(string separator, params object[] values)
{
separator = separator ?? string.Empty;
fixed (char* pSeparator = separator)
{
- // Defer argument validation to the internal function
return AppendJoinCore(pSeparator, separator.Length, values);
}
}
- public unsafe StringBuilder AppendJoin<T>(char separator, IEnumerable<T> values)
+ public unsafe StringBuilder AppendJoin<T>(string separator, IEnumerable<T> values)
{
- // Defer argument validation to the internal function
- return AppendJoinCore(&separator, 1, values);
+ separator = separator ?? string.Empty;
+ fixed (char* pSeparator = separator)
+ {
+ return AppendJoinCore(pSeparator, separator.Length, values);
+ }
}
- public unsafe StringBuilder AppendJoin<T>(string separator, IEnumerable<T> values)
+ public unsafe StringBuilder AppendJoin(string separator, params string[] values)
{
separator = separator ?? string.Empty;
fixed (char* pSeparator = separator)
{
- // Defer argument validation to the internal function
return AppendJoinCore(pSeparator, separator.Length, values);
}
}
- private unsafe StringBuilder AppendJoinCore<T>(char* separator, int separatorLength, params T[] values)
+ public unsafe StringBuilder AppendJoin(char separator, params object[] values)
{
- if (values == null)
- throw new ArgumentNullException(nameof(values));
- Contract.Ensures(Contract.Result<StringBuilder>() != null);
-
- if (values.Length == 0)
- return this;
+ return AppendJoinCore(&separator, 1, values);
+ }
- var value = values[0];
- if (value != null)
- Append(value.ToString());
+ public unsafe StringBuilder AppendJoin<T>(char separator, IEnumerable<T> values)
+ {
+ return AppendJoinCore(&separator, 1, values);
+ }
- for (var i = 1; i < values.Length; i++)
- {
- Append(separator, separatorLength);
- value = values[i];
- if (value != null)
- Append(value.ToString());
- }
- return this;
+ public unsafe StringBuilder AppendJoin(char separator, params string[] values)
+ {
+ return AppendJoinCore(&separator, 1, values);
}
+
private unsafe StringBuilder AppendJoinCore<T>(char* separator, int separatorLength, IEnumerable<T> values)
{
if (values == null)
- throw new ArgumentNullException(nameof(values));
- Contract.Ensures(Contract.Result<StringBuilder>() != null);
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values);
using (var en = values.GetEnumerator())
{
@@ -1163,6 +1152,29 @@ namespace System.Text
return this;
}
+ private unsafe StringBuilder AppendJoinCore<T>(char* separator, int separatorLength, T[] values)
+ {
+ if (values == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values);
+
+ if (values.Length == 0)
+ return this;
+
+ if (values[0] != null)
+ Append(values[0].ToString());
+
+ for (var i = 1; i < values.Length; i++)
+ {
+ Append(separator, separatorLength);
+ if (values[i] != null)
+ Append(values[i].ToString());
+ }
+ return this;
+ }
+
+ #endregion
+
+
/*====================================Insert====================================
**
==============================================================================*/
diff --git a/src/mscorlib/shared/System/Threading/Tasks/TaskExtensions.cs b/src/mscorlib/shared/System/Threading/Tasks/TaskExtensions.cs
index 1098299517..97f2013d79 100644
--- a/src/mscorlib/shared/System/Threading/Tasks/TaskExtensions.cs
+++ b/src/mscorlib/shared/System/Threading/Tasks/TaskExtensions.cs
@@ -21,7 +21,7 @@ namespace System.Threading.Tasks
// it completed successfully. Return its inner task to avoid unnecessary wrapping, or if the inner
// task is null, return a canceled task to match the same semantics as CreateUnwrapPromise.
return
- !task.IsRanToCompletion ? Task.CreateUnwrapPromise<VoidTaskResult>(task, lookForOce: false) :
+ !task.IsCompletedSuccessfully ? Task.CreateUnwrapPromise<VoidTaskResult>(task, lookForOce: false) :
task.Result ??
Task.FromCanceled(new CancellationToken(true));
}
@@ -40,7 +40,7 @@ namespace System.Threading.Tasks
// it completed successfully. Return its inner task to avoid unnecessary wrapping, or if the inner
// task is null, return a canceled task to match the same semantics as CreateUnwrapPromise.
return
- !task.IsRanToCompletion ? Task.CreateUnwrapPromise<TResult>(task, lookForOce: false) :
+ !task.IsCompletedSuccessfully ? Task.CreateUnwrapPromise<TResult>(task, lookForOce: false) :
task.Result ??
Task.FromCanceled<TResult>(new CancellationToken(true));
}