summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System')
-rw-r--r--src/mscorlib/src/System/Collections/Generic/Dictionary.cs89
-rw-r--r--src/mscorlib/src/System/Collections/Generic/List.cs1
-rw-r--r--src/mscorlib/src/System/Delegate.cs5
-rw-r--r--src/mscorlib/src/System/Environment.cs2
-rw-r--r--src/mscorlib/src/System/Globalization/CompareInfo.cs48
-rw-r--r--src/mscorlib/src/System/Globalization/HijriCalendar.Win32.cs61
-rw-r--r--src/mscorlib/src/System/Globalization/JapaneseCalendar.Win32.cs38
-rw-r--r--src/mscorlib/src/System/IO/Stream.cs4
-rw-r--r--src/mscorlib/src/System/ReadOnlySpan.cs313
-rw-r--r--src/mscorlib/src/System/Reflection/Assembly.CoreCLR.cs24
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs9
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs3
-rw-r--r--src/mscorlib/src/System/Span.cs910
-rw-r--r--src/mscorlib/src/System/String.Manipulation.cs7
-rw-r--r--src/mscorlib/src/System/String.cs2
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/Task.cs3
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs2
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/future.cs6
-rw-r--r--src/mscorlib/src/System/ThrowHelper.cs1
-rw-r--r--src/mscorlib/src/System/TimeZoneInfo.Win32.cs30
-rw-r--r--src/mscorlib/src/System/TimeZoneInfo.cs114
22 files changed, 297 insertions, 1377 deletions
diff --git a/src/mscorlib/src/System/Collections/Generic/Dictionary.cs b/src/mscorlib/src/System/Collections/Generic/Dictionary.cs
index 409b23b541..e360eef897 100644
--- a/src/mscorlib/src/System/Collections/Generic/Dictionary.cs
+++ b/src/mscorlib/src/System/Collections/Generic/Dictionary.cs
@@ -48,6 +48,7 @@ namespace System.Collections.Generic
using System.Collections;
using System.Diagnostics;
using System.Diagnostics.Contracts;
+ using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
/// <summary>
@@ -428,8 +429,7 @@ namespace System.Collections.Generic
if (buckets == null) Initialize(0);
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
- int targetBucket = hashCode % buckets.Length;
-
+ int targetBucket = hashCode % buckets.Length;
#if FEATURE_RANDOMIZED_STRING_HASHING
int collisionCount = 0;
#endif
@@ -452,7 +452,6 @@ namespace System.Collections.Generic
return false;
}
-
#if FEATURE_RANDOMIZED_STRING_HASHING
collisionCount++;
#endif
@@ -599,27 +598,40 @@ namespace System.Collections.Generic
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
int bucket = hashCode % buckets.Length;
int last = -1;
- for (int i = buckets[bucket]; i >= 0; last = i, i = entries[i].next)
+ int i = buckets[bucket];
+ while (i >= 0)
{
- if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key))
+ ref Entry entry = ref entries[i];
+
+ if (entry.hashCode == hashCode && comparer.Equals(entry.key, key))
{
if (last < 0)
{
- buckets[bucket] = entries[i].next;
+ buckets[bucket] = entry.next;
}
else
{
- entries[last].next = entries[i].next;
+ entries[last].next = entry.next;
+ }
+ entry.hashCode = -1;
+ entry.next = freeList;
+
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<TKey>())
+ {
+ entry.key = default(TKey);
+ }
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<TValue>())
+ {
+ entry.value = default(TValue);
}
- entries[i].hashCode = -1;
- entries[i].next = freeList;
- entries[i].key = default(TKey);
- entries[i].value = default(TValue);
freeList = i;
freeCount++;
version++;
return true;
}
+
+ last = i;
+ i = entry.next;
}
}
return false;
@@ -640,30 +652,43 @@ namespace System.Collections.Generic
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
int bucket = hashCode % buckets.Length;
int last = -1;
- for (int i = buckets[bucket]; i >= 0; last = i, i = entries[i].next)
+ int i = buckets[bucket];
+ while (i >= 0)
{
- if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key))
+ ref Entry entry = ref entries[i];
+
+ if (entry.hashCode == hashCode && comparer.Equals(entry.key, key))
{
if (last < 0)
{
- buckets[bucket] = entries[i].next;
+ buckets[bucket] = entry.next;
}
else
{
- entries[last].next = entries[i].next;
+ entries[last].next = entry.next;
}
- value = entries[i].value;
+ value = entry.value;
- entries[i].hashCode = -1;
- entries[i].next = freeList;
- entries[i].key = default(TKey);
- entries[i].value = default(TValue);
+ entry.hashCode = -1;
+ entry.next = freeList;
+
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<TKey>())
+ {
+ entry.key = default(TKey);
+ }
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<TValue>())
+ {
+ entry.value = default(TValue);
+ }
freeList = i;
freeCount++;
version++;
return true;
}
+
+ last = i;
+ i = entry.next;
}
}
value = default(TValue);
@@ -955,13 +980,13 @@ namespace System.Collections.Generic
// dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue
while ((uint)index < (uint)dictionary.count)
{
- if (dictionary.entries[index].hashCode >= 0)
+ ref Entry entry = ref dictionary.entries[index++];
+
+ if (entry.hashCode >= 0)
{
- current = new KeyValuePair<TKey, TValue>(dictionary.entries[index].key, dictionary.entries[index].value);
- index++;
+ current = new KeyValuePair<TKey, TValue>(entry.key, entry.value);
return true;
}
- index++;
}
index = dictionary.count + 1;
@@ -1231,13 +1256,13 @@ namespace System.Collections.Generic
while ((uint)index < (uint)dictionary.count)
{
- if (dictionary.entries[index].hashCode >= 0)
+ ref Entry entry = ref dictionary.entries[index++];
+
+ if (entry.hashCode >= 0)
{
- currentKey = dictionary.entries[index].key;
- index++;
+ currentKey = entry.key;
return true;
}
- index++;
}
index = dictionary.count + 1;
@@ -1459,13 +1484,13 @@ namespace System.Collections.Generic
while ((uint)index < (uint)dictionary.count)
{
- if (dictionary.entries[index].hashCode >= 0)
+ ref Entry entry = ref dictionary.entries[index++];
+
+ if (entry.hashCode >= 0)
{
- currentValue = dictionary.entries[index].value;
- index++;
+ currentValue = entry.value;
return true;
}
- index++;
}
index = dictionary.count + 1;
currentValue = default(TValue);
diff --git a/src/mscorlib/src/System/Collections/Generic/List.cs b/src/mscorlib/src/System/Collections/Generic/List.cs
index 67d1668aad..4e480885ef 100644
--- a/src/mscorlib/src/System/Collections/Generic/List.cs
+++ b/src/mscorlib/src/System/Collections/Generic/List.cs
@@ -350,6 +350,7 @@ namespace System.Collections.Generic
// Clears the contents of List.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
diff --git a/src/mscorlib/src/System/Delegate.cs b/src/mscorlib/src/System/Delegate.cs
index de0ff6532c..75ec57a003 100644
--- a/src/mscorlib/src/System/Delegate.cs
+++ b/src/mscorlib/src/System/Delegate.cs
@@ -179,7 +179,10 @@ namespace System
else
return unchecked((int)((long)this._methodPtrAux));
*/
- return GetType().GetHashCode();
+ if (_methodPtrAux.IsNull())
+ return ( _target != null ? RuntimeHelpers.GetHashCode(_target) * 33 : 0) + GetType().GetHashCode();
+ else
+ return GetType().GetHashCode();
}
public static Delegate Combine(Delegate a, Delegate b)
diff --git a/src/mscorlib/src/System/Environment.cs b/src/mscorlib/src/System/Environment.cs
index b9070ae713..dddbdc242d 100644
--- a/src/mscorlib/src/System/Environment.cs
+++ b/src/mscorlib/src/System/Environment.cs
@@ -820,7 +820,7 @@ namespace System
}
else
{
- environmentKey.SetStringValue(variable, value);
+ environmentKey.SetValue(variable, value);
}
}
}
diff --git a/src/mscorlib/src/System/Globalization/CompareInfo.cs b/src/mscorlib/src/System/Globalization/CompareInfo.cs
index 285a81d906..b2c2208db7 100644
--- a/src/mscorlib/src/System/Globalization/CompareInfo.cs
+++ b/src/mscorlib/src/System/Globalization/CompareInfo.cs
@@ -752,7 +752,6 @@ namespace System.Globalization
return IndexOfCore(source, new string(value, 1), startIndex, count, options, null);
}
-
public unsafe virtual int IndexOf(string source, string value, int startIndex, int count, CompareOptions options)
{
// Validate inputs
@@ -802,6 +801,53 @@ namespace System.Globalization
return IndexOfCore(source, value, startIndex, count, options, null);
}
+ // The following IndexOf overload is mainly used by String.Replace. This overload assumes the parameters are already validated
+ // and the caller is passing a valid matchLengthPtr pointer.
+ internal unsafe int IndexOf(string source, string value, int startIndex, int count, CompareOptions options, int* matchLengthPtr)
+ {
+ Debug.Assert(source != null);
+ Debug.Assert(value != null);
+ Debug.Assert(startIndex >= 0);
+ Debug.Assert(matchLengthPtr != null);
+ *matchLengthPtr = 0;
+
+ if (source.Length == 0)
+ {
+ if (value.Length == 0)
+ {
+ return 0;
+ }
+ return -1;
+ }
+
+ if (startIndex >= source.Length)
+ {
+ return -1;
+ }
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ int res = IndexOfOrdinal(source, value, startIndex, count, ignoreCase: true);
+ if (res >= 0)
+ {
+ *matchLengthPtr = value.Length;
+ }
+ return res;
+ }
+
+ if (_invariantMode)
+ {
+ int res = IndexOfOrdinal(source, value, startIndex, count, ignoreCase: (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0);
+ if (res >= 0)
+ {
+ *matchLengthPtr = value.Length;
+ }
+ return res;
+ }
+
+ return IndexOfCore(source, value, startIndex, count, options, matchLengthPtr);
+ }
+
internal int IndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase)
{
if (_invariantMode)
diff --git a/src/mscorlib/src/System/Globalization/HijriCalendar.Win32.cs b/src/mscorlib/src/System/Globalization/HijriCalendar.Win32.cs
index 4ba95c8fa8..869b809bff 100644
--- a/src/mscorlib/src/System/Globalization/HijriCalendar.Win32.cs
+++ b/src/mscorlib/src/System/Globalization/HijriCalendar.Win32.cs
@@ -42,41 +42,54 @@ namespace System.Globalization
int hijriAdvance = 0;
Microsoft.Win32.RegistryKey key = null;
- using (key = Registry.CurrentUser.OpenSubKey(InternationalRegKey, writable: false))
+ try
{
- if (key == null)
- return 0;
+ // Open in read-only mode.
+ // Use InternalOpenSubKey so that we avoid the security check.
+ key = RegistryKey.GetBaseKey(RegistryKey.HKEY_CURRENT_USER).OpenSubKey(InternationalRegKey, false);
+ }
+ //If this fails for any reason, we'll just return 0.
+ catch (ObjectDisposedException) { return 0; }
+ catch (ArgumentException) { return 0; }
- Object value = key.GetValue(HijriAdvanceRegKeyEntry);
- if (value == null)
- {
- return (0);
- }
- String str = value.ToString();
- if (String.Compare(str, 0, HijriAdvanceRegKeyEntry, 0, HijriAdvanceRegKeyEntry.Length, StringComparison.OrdinalIgnoreCase) == 0)
+ if (key != null)
+ {
+ try
{
- if (str.Length == HijriAdvanceRegKeyEntry.Length)
- hijriAdvance = -1;
- else
+ Object value = key.InternalGetValue(HijriAdvanceRegKeyEntry, null, false, false);
+ if (value == null)
{
- str = str.Substring(HijriAdvanceRegKeyEntry.Length);
- try
+ return (0);
+ }
+ String str = value.ToString();
+ if (String.Compare(str, 0, HijriAdvanceRegKeyEntry, 0, HijriAdvanceRegKeyEntry.Length, StringComparison.OrdinalIgnoreCase) == 0)
+ {
+ if (str.Length == HijriAdvanceRegKeyEntry.Length)
+ hijriAdvance = -1;
+ else
{
- int advance = Int32.Parse(str.ToString(), CultureInfo.InvariantCulture);
- if ((advance >= MinAdvancedHijri) && (advance <= MaxAdvancedHijri))
+ str = str.Substring(HijriAdvanceRegKeyEntry.Length);
+ try
{
- hijriAdvance = advance;
+ int advance = Int32.Parse(str.ToString(), CultureInfo.InvariantCulture);
+ if ((advance >= MinAdvancedHijri) && (advance <= MaxAdvancedHijri))
+ {
+ hijriAdvance = advance;
+ }
}
+ // If we got garbage from registry just ignore it.
+ // hijriAdvance = 0 because of declaraction assignment up above.
+ catch (ArgumentException) { }
+ catch (FormatException) { }
+ catch (OverflowException) { }
}
- // If we got garbage from registry just ignore it.
- // hijriAdvance = 0 because of declaraction assignment up above.
- catch (ArgumentException) { }
- catch (FormatException) { }
- catch (OverflowException) { }
}
}
+ finally
+ {
+ key.Close();
+ }
}
-
return (hijriAdvance);
}
}
diff --git a/src/mscorlib/src/System/Globalization/JapaneseCalendar.Win32.cs b/src/mscorlib/src/System/Globalization/JapaneseCalendar.Win32.cs
index fe8b1b5896..a83c4fad9e 100644
--- a/src/mscorlib/src/System/Globalization/JapaneseCalendar.Win32.cs
+++ b/src/mscorlib/src/System/Globalization/JapaneseCalendar.Win32.cs
@@ -36,30 +36,30 @@ namespace System.Globalization
try
{
- using (RegistryKey key = Registry.LocalMachine.OpenSubKey(c_japaneseErasHive, writable: false))
+ // Need to access registry
+ RegistryKey key = RegistryKey.GetBaseKey(RegistryKey.HKEY_LOCAL_MACHINE).OpenSubKey(c_japaneseErasHive, false);
+
+ // Abort if we didn't find anything
+ if (key == null) return null;
+
+ // Look up the values in our reg key
+ String[] valueNames = key.GetValueNames();
+ if (valueNames != null && valueNames.Length > 0)
{
- // Abort if we didn't find anything
- if (key == null) return null;
+ registryEraRanges = new EraInfo[valueNames.Length];
- // Look up the values in our reg key
- String[] valueNames = key.GetValueNames();
- if (valueNames != null && valueNames.Length > 0)
+ // Loop through the registry and read in all the values
+ for (int i = 0; i < valueNames.Length; i++)
{
- registryEraRanges = new EraInfo[valueNames.Length];
-
- // Loop through the registry and read in all the values
- for (int i = 0; i < valueNames.Length; i++)
- {
- // See if the era is a valid date
- EraInfo era = GetEraFromValue(valueNames[i], key.GetValue(valueNames[i]).ToString());
+ // See if the era is a valid date
+ EraInfo era = GetEraFromValue(valueNames[i], key.GetValue(valueNames[i]).ToString());
- // continue if not valid
- if (era == null) continue;
+ // continue if not valid
+ if (era == null) continue;
- // Remember we found one.
- registryEraRanges[iFoundEras] = era;
- iFoundEras++;
- }
+ // Remember we found one.
+ registryEraRanges[iFoundEras] = era;
+ iFoundEras++;
}
}
}
diff --git a/src/mscorlib/src/System/IO/Stream.cs b/src/mscorlib/src/System/IO/Stream.cs
index 92fe374f19..65cc4ddcb9 100644
--- a/src/mscorlib/src/System/IO/Stream.cs
+++ b/src/mscorlib/src/System/IO/Stream.cs
@@ -522,14 +522,14 @@ namespace System.IO
// If the wait has already completed, run the task.
if (asyncWaiter.IsCompleted)
{
- Debug.Assert(asyncWaiter.IsRanToCompletion, "The semaphore wait should always complete successfully.");
+ Debug.Assert(asyncWaiter.IsCompletedSuccessfully, "The semaphore wait should always complete successfully.");
RunReadWriteTask(readWriteTask);
}
else // Otherwise, wait for our turn, and then run the task.
{
asyncWaiter.ContinueWith((t, state) =>
{
- Debug.Assert(t.IsRanToCompletion, "The semaphore wait should always complete successfully.");
+ Debug.Assert(t.IsCompletedSuccessfully, "The semaphore wait should always complete successfully.");
var rwt = (ReadWriteTask)state;
rwt._stream.RunReadWriteTask(rwt); // RunReadWriteTask(readWriteTask);
}, readWriteTask, default(CancellationToken), TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
diff --git a/src/mscorlib/src/System/ReadOnlySpan.cs b/src/mscorlib/src/System/ReadOnlySpan.cs
deleted file mode 100644
index 8d0fbad0fc..0000000000
--- a/src/mscorlib/src/System/ReadOnlySpan.cs
+++ /dev/null
@@ -1,313 +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.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>
- 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 JitHelpers.GetArrayData(array));
- _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 JitHelpers.GetArrayData(array), 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 JitHelpers.GetArrayData(array), 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]
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get
- {
- if ((uint)index >= (uint)_length)
- ThrowHelper.ThrowIndexOutOfRangeException();
-
- return Unsafe.Add(ref _pointer.Value, index);
- }
- }
-
- /// <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;
-
- SpanHelper.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];
- SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), 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/src/System/Reflection/Assembly.CoreCLR.cs b/src/mscorlib/src/System/Reflection/Assembly.CoreCLR.cs
index 82966dba60..708f79b64f 100644
--- a/src/mscorlib/src/System/Reflection/Assembly.CoreCLR.cs
+++ b/src/mscorlib/src/System/Reflection/Assembly.CoreCLR.cs
@@ -101,14 +101,20 @@ namespace System.Reflection
{
Contract.Ensures(Contract.Result<Assembly>() != null);
Contract.Ensures(!Contract.Result<Assembly>().ReflectionOnly);
-
+
+ AssemblyName modifiedAssemblyRef = null;
if (assemblyRef != null && assemblyRef.CodeBase != null)
{
- throw new NotSupportedException(SR.NotSupported_AssemblyLoadCodeBase);
+ modifiedAssemblyRef = (AssemblyName)assemblyRef.Clone();
+ modifiedAssemblyRef.CodeBase = null;
}
-
+ else
+ {
+ modifiedAssemblyRef = assemblyRef;
+ }
+
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return RuntimeAssembly.InternalLoadAssemblyName(assemblyRef, null, null, ref stackMark, true /*thrownOnFileNotFound*/, false /*forIntrospection*/);
+ return RuntimeAssembly.InternalLoadAssemblyName(modifiedAssemblyRef, null, null, ref stackMark, true /*thrownOnFileNotFound*/, false /*forIntrospection*/);
}
// Locate an assembly by its name. The name can be strong or
@@ -119,13 +125,19 @@ namespace System.Reflection
Contract.Ensures(Contract.Result<Assembly>() != null);
Contract.Ensures(!Contract.Result<Assembly>().ReflectionOnly);
+ AssemblyName modifiedAssemblyRef = null;
if (assemblyRef != null && assemblyRef.CodeBase != null)
{
- throw new NotSupportedException(SR.NotSupported_AssemblyLoadCodeBase);
+ modifiedAssemblyRef = (AssemblyName)assemblyRef.Clone();
+ modifiedAssemblyRef.CodeBase = null;
+ }
+ else
+ {
+ modifiedAssemblyRef = assemblyRef;
}
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return RuntimeAssembly.InternalLoadAssemblyName(assemblyRef, null, null, ref stackMark, true /*thrownOnFileNotFound*/, false /*forIntrospection*/, ptrLoadContextBinder);
+ return RuntimeAssembly.InternalLoadAssemblyName(modifiedAssemblyRef, null, null, ref stackMark, true /*thrownOnFileNotFound*/, false /*forIntrospection*/, ptrLoadContextBinder);
}
// Loads the assembly with a COFF based IMAGE containing
diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs b/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs
index e2fa6caa2d..c35658e54c 100644
--- a/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs
+++ b/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs
@@ -146,7 +146,7 @@ namespace System.Runtime.CompilerServices
task.NotifyDebuggerOfWaitCompletionIfNecessary();
// And throw an exception if the task is faulted or canceled.
- if (!task.IsRanToCompletion) ThrowForNonSuccess(task);
+ if (!task.IsCompletedSuccessfully) ThrowForNonSuccess(task);
}
/// <summary>Throws an exception to handle a task that completed in a state other than RanToCompletion.</summary>
diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs b/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs
index b86835f778..d5201350ec 100644
--- a/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs
+++ b/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs
@@ -216,14 +216,7 @@ namespace System.Runtime.CompilerServices
private extern static bool IsAddressInStack(IntPtr ptr);
#endif
- static internal bool ByRefLessThan<T>(ref T refA, ref T refB)
- {
- // The body of this function will be replaced by the EE with unsafe code!!!
- // See getILIntrinsicImplementation for how this happens.
- throw new InvalidOperationException();
- }
-
- static internal ref T GetArrayData<T>(T[] array)
+ static internal ref byte GetRawSzArrayData(this Array array)
{
// The body of this function will be replaced by the EE with unsafe code!!!
// See getILIntrinsicImplementation for how this happens.
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs b/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs
index 248e0d5778..6fb631121b 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs
@@ -824,6 +824,9 @@ namespace System.Runtime.InteropServices
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public static extern /* struct _EXCEPTION_POINTERS* */ IntPtr GetExceptionPointers();
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern int GetExceptionCode();
diff --git a/src/mscorlib/src/System/Span.cs b/src/mscorlib/src/System/Span.cs
deleted file mode 100644
index 4211083def..0000000000
--- a/src/mscorlib/src/System/Span.cs
+++ /dev/null
@@ -1,910 +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.Diagnostics;
-using System.Runtime;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-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>
- 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 JitHelpers.GetArrayData(array));
- _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 JitHelpers.GetArrayData(array), 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 JitHelpers.GetArrayData(array), 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]
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get
- {
- if ((uint)index >= (uint)_length)
- ThrowHelper.ThrowIndexOutOfRangeException();
-
- return ref Unsafe.Add(ref _pointer.Value, index);
- }
- }
-
- /// <summary>
- /// Clears the contents of this span.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Clear()
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- {
- SpanHelper.ClearWithReferences(ref Unsafe.As<T, IntPtr>(ref _pointer.Value), (nuint)_length * (nuint)(Unsafe.SizeOf<T>() / sizeof(nuint)));
- }
- else
- {
- SpanHelper.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;
-
- SpanHelper.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];
- SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref _pointer.Value, _length);
- return destination;
- }
-
- // <summary>
- /// Returns an empty <see cref="Span{T}"/>
- /// </summary>
- public static Span<T> Empty => default(Span<T>);
- }
-
- 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.GetFirstCharRef(), text.Length);
- }
- }
-
- internal static class SpanHelper
- {
- 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
- if (byteLength > 4096) goto PInvoke;
- Unsafe.InitBlockUnaligned(ref b, 0, (uint)byteLength);
- return;
-#else // AMD64
- // TODO: Optimize this method on X86 machine
- // 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 // AMD64
-
- 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/src/System/String.Manipulation.cs b/src/mscorlib/src/System/String.Manipulation.cs
index 33e341c58e..b71ffa2f63 100644
--- a/src/mscorlib/src/System/String.Manipulation.cs
+++ b/src/mscorlib/src/System/String.Manipulation.cs
@@ -1022,8 +1022,10 @@ namespace System
{
if (oldValue == null)
throw new ArgumentNullException(nameof(oldValue));
+ if (oldValue.Length == 0)
+ throw new ArgumentException(SR.Argument_StringZeroLength, nameof(oldValue));
- // If they asked to replace oldValue with a null, replace all occurences
+ // If they asked to replace oldValue with a null, replace all occurrences
// with the empty string.
if (newValue == null)
newValue = string.Empty;
@@ -1037,10 +1039,11 @@ namespace System
int matchLength = 0;
bool hasDoneAnyReplacements = false;
+ CompareInfo ci = referenceCulture.CompareInfo;
do
{
- index = referenceCulture.CompareInfo.IndexOfCore(this, oldValue, startIndex, m_stringLength - startIndex, options, &matchLength);
+ index = ci.IndexOf(this, oldValue, startIndex, m_stringLength - startIndex, options, &matchLength);
if (index >= 0)
{
// append the unmodified portion of string
diff --git a/src/mscorlib/src/System/String.cs b/src/mscorlib/src/System/String.cs
index f3a4d0f197..0a17c1ee24 100644
--- a/src/mscorlib/src/System/String.cs
+++ b/src/mscorlib/src/System/String.cs
@@ -876,7 +876,7 @@ namespace System
}
}
- internal ref char GetFirstCharRef()
+ internal ref char GetRawStringData()
{
return ref m_firstChar;
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/Task.cs b/src/mscorlib/src/System/Threading/Tasks/Task.cs
index 8e2e6a4cb0..0a9248cba8 100644
--- a/src/mscorlib/src/System/Threading/Tasks/Task.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/Task.cs
@@ -1467,8 +1467,7 @@ namespace System.Threading.Tasks
return (flags & TASK_STATE_COMPLETED_MASK) != 0;
}
- // For use in InternalWait -- marginally faster than (Task.Status == TaskStatus.RanToCompletion)
- internal bool IsRanToCompletion
+ public bool IsCompletedSuccessfully
{
get { return (m_stateFlags & TASK_STATE_COMPLETED_MASK) == TASK_STATE_RAN_TO_COMPLETION; }
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs b/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs
index 848a0ecbc2..de222352c9 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs
@@ -320,7 +320,7 @@ namespace System.Threading.Tasks
// activation criteria of the TaskContinuationOptions.
TaskContinuationOptions options = m_options;
bool isRightKind =
- completedTask.IsRanToCompletion ?
+ completedTask.IsCompletedSuccessfully ?
(options & TaskContinuationOptions.NotOnRanToCompletion) == 0 :
(completedTask.IsCanceled ?
(options & TaskContinuationOptions.NotOnCanceled) == 0 :
diff --git a/src/mscorlib/src/System/Threading/Tasks/future.cs b/src/mscorlib/src/System/Threading/Tasks/future.cs
index 26c2388e6b..bf9000ea00 100644
--- a/src/mscorlib/src/System/Threading/Tasks/future.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/future.cs
@@ -374,7 +374,7 @@ namespace System.Threading.Tasks
{
get
{
- return IsRanToCompletion ? "" + m_result : SR.TaskT_DebuggerNoResult;
+ return IsCompletedSuccessfully ? "" + m_result : SR.TaskT_DebuggerNoResult;
}
}
@@ -491,10 +491,10 @@ namespace System.Threading.Tasks
if (waitCompletionNotification) NotifyDebuggerOfWaitCompletionIfNecessary();
// Throw an exception if appropriate.
- if (!IsRanToCompletion) ThrowIfExceptional(includeTaskCanceledExceptions: true);
+ if (!IsCompletedSuccessfully) ThrowIfExceptional(includeTaskCanceledExceptions: true);
// We shouldn't be here if the result has not been set.
- Debug.Assert(IsRanToCompletion, "Task<T>.Result getter: Expected result to have been set.");
+ Debug.Assert(IsCompletedSuccessfully, "Task<T>.Result getter: Expected result to have been set.");
return m_result;
}
diff --git a/src/mscorlib/src/System/ThrowHelper.cs b/src/mscorlib/src/System/ThrowHelper.cs
index 4dcf8d4511..ff76738e8e 100644
--- a/src/mscorlib/src/System/ThrowHelper.cs
+++ b/src/mscorlib/src/System/ThrowHelper.cs
@@ -416,6 +416,7 @@ namespace System
type,
stateMachine,
pHandle,
+ values
}
//
diff --git a/src/mscorlib/src/System/TimeZoneInfo.Win32.cs b/src/mscorlib/src/System/TimeZoneInfo.Win32.cs
index b6585bd0a0..4f740bd355 100644
--- a/src/mscorlib/src/System/TimeZoneInfo.Win32.cs
+++ b/src/mscorlib/src/System/TimeZoneInfo.Win32.cs
@@ -398,7 +398,7 @@ namespace System
baseOffset = baseOffset + match.Rule.BaseUtcOffsetDelta;
if (match.Rule.HasDaylightSaving)
{
- isDaylightSavings = GetIsDaylightSavingsFromUtc(time, timeYear, match.Offset, match.Rule, out isAmbiguousLocalDst, Local);
+ isDaylightSavings = GetIsDaylightSavingsFromUtc(time, timeYear, match.Offset, match.Rule, null, out isAmbiguousLocalDst, Local);
baseOffset += (isDaylightSavings ? match.Rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */);
}
}
@@ -576,8 +576,8 @@ namespace System
// read LastEntry {(yearN, 1, 1) - MaxValue }
// read the FirstEntry and LastEntry key values (ex: "1980", "2038")
- int first = (int)dynamicKey.GetValue(FirstEntryValue, -1);
- int last = (int)dynamicKey.GetValue(LastEntryValue, -1);
+ int first = (int)dynamicKey.GetValue(FirstEntryValue, -1, RegistryValueOptions.None);
+ int last = (int)dynamicKey.GetValue(LastEntryValue, -1, RegistryValueOptions.None);
if (first == -1 || last == -1 || first > last)
{
@@ -587,7 +587,7 @@ namespace System
// read the first year entry
Win32Native.RegistryTimeZoneInformation dtzi;
- byte[] regValue = dynamicKey.GetValue(first.ToString(CultureInfo.InvariantCulture)) as byte[];
+ byte[] regValue = dynamicKey.GetValue(first.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as byte[];
if (regValue == null || regValue.Length != RegByteLength)
{
rules = null;
@@ -620,7 +620,7 @@ namespace System
// read the middle year entries
for (int i = first + 1; i < last; i++)
{
- regValue = dynamicKey.GetValue(i.ToString(CultureInfo.InvariantCulture)) as byte[];
+ regValue = dynamicKey.GetValue(i.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as byte[];
if (regValue == null || regValue.Length != RegByteLength)
{
rules = null;
@@ -640,7 +640,7 @@ namespace System
}
// read the last year entry
- regValue = dynamicKey.GetValue(last.ToString(CultureInfo.InvariantCulture)) as byte[];
+ regValue = dynamicKey.GetValue(last.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as byte[];
dtzi = new Win32Native.RegistryTimeZoneInformation(regValue);
if (regValue == null || regValue.Length != RegByteLength)
{
@@ -719,7 +719,7 @@ namespace System
}
Win32Native.RegistryTimeZoneInformation registryTimeZoneInfo;
- byte[] regValue = key.GetValue(TimeZoneInfoValue) as byte[];
+ byte[] regValue = key.GetValue(TimeZoneInfoValue, null, RegistryValueOptions.None) as byte[];
if (regValue == null || regValue.Length != RegByteLength) return false;
registryTimeZoneInfo = new Win32Native.RegistryTimeZoneInformation(regValue);
@@ -756,7 +756,7 @@ namespace System
//
if (result)
{
- string registryStandardName = key.GetValue(StandardValue, string.Empty) as string;
+ string registryStandardName = key.GetValue(StandardValue, string.Empty, RegistryValueOptions.None) as string;
result = string.Equals(registryStandardName, timeZone.StandardName, StringComparison.Ordinal);
}
return result;
@@ -884,9 +884,9 @@ namespace System
daylightName = string.Empty;
// read the MUI_ registry keys
- string displayNameMuiResource = key.GetValue(MuiDisplayValue, string.Empty) as string;
- string standardNameMuiResource = key.GetValue(MuiStandardValue, string.Empty) as string;
- string daylightNameMuiResource = key.GetValue(MuiDaylightValue, string.Empty) as string;
+ string displayNameMuiResource = key.GetValue(MuiDisplayValue, string.Empty, RegistryValueOptions.None) as string;
+ string standardNameMuiResource = key.GetValue(MuiStandardValue, string.Empty, RegistryValueOptions.None) as string;
+ string daylightNameMuiResource = key.GetValue(MuiDaylightValue, string.Empty, RegistryValueOptions.None) as string;
// try to load the strings from the native resource DLL(s)
if (!string.IsNullOrEmpty(displayNameMuiResource))
@@ -907,15 +907,15 @@ namespace System
// fallback to using the standard registry keys
if (string.IsNullOrEmpty(displayName))
{
- displayName = key.GetValue(DisplayValue, string.Empty) as string;
+ displayName = key.GetValue(DisplayValue, string.Empty, RegistryValueOptions.None) as string;
}
if (string.IsNullOrEmpty(standardName))
{
- standardName = key.GetValue(StandardValue, string.Empty) as string;
+ standardName = key.GetValue(StandardValue, string.Empty, RegistryValueOptions.None) as string;
}
if (string.IsNullOrEmpty(daylightName))
{
- daylightName = key.GetValue(DaylightValue, string.Empty) as string;
+ daylightName = key.GetValue(DaylightValue, string.Empty, RegistryValueOptions.None) as string;
}
return true;
@@ -964,7 +964,7 @@ namespace System
}
Win32Native.RegistryTimeZoneInformation defaultTimeZoneInformation;
- byte[] regValue = key.GetValue(TimeZoneInfoValue) as byte[];
+ byte[] regValue = key.GetValue(TimeZoneInfoValue, null, RegistryValueOptions.None) as byte[];
if (regValue == null || regValue.Length != RegByteLength)
{
// the registry value could not be cast to a byte array
diff --git a/src/mscorlib/src/System/TimeZoneInfo.cs b/src/mscorlib/src/System/TimeZoneInfo.cs
index 29ea33a8ad..8ed7e229c0 100644
--- a/src/mscorlib/src/System/TimeZoneInfo.cs
+++ b/src/mscorlib/src/System/TimeZoneInfo.cs
@@ -172,10 +172,11 @@ namespace System
DateTime adjustedTime = ConvertTime(dateTimeOffset, this).DateTime;
bool isAmbiguous = false;
- AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime);
+ int? ruleIndex;
+ AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out ruleIndex);
if (rule != null && rule.HasDaylightSaving)
{
- DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule);
+ DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex);
isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime);
}
@@ -232,10 +233,11 @@ namespace System
}
bool isAmbiguous = false;
- AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime);
+ int? ruleIndex;
+ AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out ruleIndex);
if (rule != null && rule.HasDaylightSaving)
{
- DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule);
+ DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex);
isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime);
}
@@ -263,15 +265,15 @@ namespace System
}
// note the time is already adjusted
- private AdjustmentRule GetAdjustmentRuleForAmbiguousOffsets(DateTime adjustedTime)
+ private AdjustmentRule GetAdjustmentRuleForAmbiguousOffsets(DateTime adjustedTime, out int? ruleIndex)
{
- AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime);
+ AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex);
if (rule != null && rule.NoDaylightTransitions && !rule.HasDaylightSaving)
{
// When using NoDaylightTransitions rules, each rule is only for one offset.
// When looking for the Daylight savings rules, and we found the non-DST rule,
// then we get the rule right before this rule.
- return GetPreviousAdjustmentRule(rule);
+ return GetPreviousAdjustmentRule(rule, ruleIndex);
}
return rule;
@@ -282,12 +284,23 @@ namespace System
/// If the specified rule is the first AdjustmentRule, or it isn't in _adjustmentRules,
/// then the specified rule is returned.
/// </summary>
- private AdjustmentRule GetPreviousAdjustmentRule(AdjustmentRule rule)
+ private AdjustmentRule GetPreviousAdjustmentRule(AdjustmentRule rule, int? ruleIndex)
{
+ Debug.Assert(rule.NoDaylightTransitions, "GetPreviousAdjustmentRule should only be used with NoDaylightTransitions rules.");
+
+ if (ruleIndex.HasValue && 0 < ruleIndex.Value && ruleIndex.Value < _adjustmentRules.Length)
+ {
+ return _adjustmentRules[ruleIndex.Value - 1];
+ }
+
AdjustmentRule result = rule;
for (int i = 1; i < _adjustmentRules.Length; i++)
{
- if (rule.Equals(_adjustmentRules[i]))
+ // use ReferenceEquals here instead of AdjustmentRule.Equals because
+ // ReferenceEquals is much faster. This is safe because all the callers
+ // of GetPreviousAdjustmentRule pass in a rule that was retrieved from
+ // _adjustmentRules. A different approach will be needed if this ever changes.
+ if (ReferenceEquals(rule, _adjustmentRules[i]))
{
result = _adjustmentRules[i - 1];
break;
@@ -407,10 +420,11 @@ namespace System
dateTime.Kind == DateTimeKind.Utc ? ConvertTime(dateTime, s_utcTimeZone, this, flags, cachedData) :
dateTime;
- AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime);
+ int? ruleIndex;
+ AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex);
if (rule != null && rule.HasDaylightSaving)
{
- DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule);
+ DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex);
return GetIsAmbiguousTime(adjustedTime, rule, daylightTime);
}
return false;
@@ -492,10 +506,11 @@ namespace System
//
// handle the normal cases...
//
- AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime);
+ int? ruleIndex;
+ AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex);
if (rule != null && rule.HasDaylightSaving)
{
- DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule);
+ DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex);
return GetIsDaylightSavings(adjustedTime, rule, daylightTime, flags);
}
else
@@ -515,11 +530,12 @@ namespace System
(dateTime.Kind == DateTimeKind.Local && s_cachedData.GetCorrespondingKind(this) == DateTimeKind.Local))
{
// only check Unspecified and (Local when this TimeZoneInfo instance is Local)
- AdjustmentRule rule = GetAdjustmentRuleForTime(dateTime);
+ int? ruleIndex;
+ AdjustmentRule rule = GetAdjustmentRuleForTime(dateTime, out ruleIndex);
if (rule != null && rule.HasDaylightSaving)
{
- DaylightTimeStruct daylightTime = GetDaylightTime(dateTime.Year, rule);
+ DaylightTimeStruct daylightTime = GetDaylightTime(dateTime.Year, rule, ruleIndex);
isInvalid = GetIsInvalidTime(dateTime, rule, daylightTime);
}
else
@@ -661,7 +677,8 @@ namespace System
// performance for the normal case at the expense of the 'ArgumentException'
// case and Loss-less Local special cases.
//
- AdjustmentRule sourceRule = sourceTimeZone.GetAdjustmentRuleForTime(dateTime);
+ int? sourceRuleIndex;
+ AdjustmentRule sourceRule = sourceTimeZone.GetAdjustmentRuleForTime(dateTime, out sourceRuleIndex);
TimeSpan sourceOffset = sourceTimeZone.BaseUtcOffset;
if (sourceRule != null)
@@ -670,7 +687,7 @@ namespace System
if (sourceRule.HasDaylightSaving)
{
bool sourceIsDaylightSavings = false;
- DaylightTimeStruct sourceDaylightTime = sourceTimeZone.GetDaylightTime(dateTime.Year, sourceRule);
+ DaylightTimeStruct sourceDaylightTime = sourceTimeZone.GetDaylightTime(dateTime.Year, sourceRule, sourceRuleIndex);
// 'dateTime' might be in an invalid time range since it is in an AdjustmentRule
// period that supports DST
@@ -1048,10 +1065,19 @@ namespace System
_supportsDaylightSavingTime = (bool)info.GetValue("SupportsDaylightSavingTime", typeof(bool));
}
- private AdjustmentRule GetAdjustmentRuleForTime(DateTime dateTime, bool dateTimeisUtc = false)
+ private AdjustmentRule GetAdjustmentRuleForTime(DateTime dateTime, out int? ruleIndex)
+ {
+ AdjustmentRule result = GetAdjustmentRuleForTime(dateTime, dateTimeisUtc: false, ruleIndex: out ruleIndex);
+ Debug.Assert(result == null || ruleIndex.HasValue, "If an AdjustmentRule was found, ruleIndex should also be set.");
+
+ return result;
+ }
+
+ private AdjustmentRule GetAdjustmentRuleForTime(DateTime dateTime, bool dateTimeisUtc, out int? ruleIndex)
{
if (_adjustmentRules == null || _adjustmentRules.Length == 0)
{
+ ruleIndex = null;
return null;
}
@@ -1076,6 +1102,7 @@ namespace System
int compareResult = CompareAdjustmentRuleToDateTime(rule, previousRule, dateTime, date, dateTimeisUtc);
if (compareResult == 0)
{
+ ruleIndex = median;
return rule;
}
else if (compareResult < 0)
@@ -1088,6 +1115,7 @@ namespace System
}
}
+ ruleIndex = null;
return null;
}
@@ -1199,7 +1227,7 @@ namespace System
/// <summary>
/// Helper function that returns a DaylightTime from a year and AdjustmentRule.
/// </summary>
- private DaylightTimeStruct GetDaylightTime(int year, AdjustmentRule rule)
+ private DaylightTimeStruct GetDaylightTime(int year, AdjustmentRule rule, int? ruleIndex)
{
TimeSpan delta = rule.DaylightDelta;
DateTime startTime;
@@ -1211,7 +1239,7 @@ namespace System
// Convert the UTC times into adjusted time zone times.
// use the previous rule to calculate the startTime, since the DST change happens w.r.t. the previous rule
- AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule);
+ AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule, ruleIndex);
startTime = ConvertFromUtc(rule.DateStart, previousRule.DaylightDelta, previousRule.BaseUtcOffsetDelta);
endTime = ConvertFromUtc(rule.DateEnd, rule.DaylightDelta, rule.BaseUtcOffsetDelta);
@@ -1301,12 +1329,12 @@ namespace System
/// <summary>
/// Gets the offset that should be used to calculate DST start times from a UTC time.
/// </summary>
- private TimeSpan GetDaylightSavingsStartOffsetFromUtc(TimeSpan baseUtcOffset, AdjustmentRule rule)
+ private TimeSpan GetDaylightSavingsStartOffsetFromUtc(TimeSpan baseUtcOffset, AdjustmentRule rule, int? ruleIndex)
{
if (rule.NoDaylightTransitions)
{
// use the previous rule to calculate the startTime, since the DST change happens w.r.t. the previous rule
- AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule);
+ AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule, ruleIndex);
return baseUtcOffset + previousRule.BaseUtcOffsetDelta + previousRule.DaylightDelta;
}
else
@@ -1328,7 +1356,7 @@ namespace System
/// Helper function that checks if a given dateTime is in Daylight Saving Time (DST).
/// This function assumes the dateTime is in UTC and AdjustmentRule is in a different time zone.
/// </summary>
- private static bool GetIsDaylightSavingsFromUtc(DateTime time, int year, TimeSpan utc, AdjustmentRule rule, out bool isAmbiguousLocalDst, TimeZoneInfo zone)
+ private static bool GetIsDaylightSavingsFromUtc(DateTime time, int year, TimeSpan utc, AdjustmentRule rule, int? ruleIndex, out bool isAmbiguousLocalDst, TimeZoneInfo zone)
{
isAmbiguousLocalDst = false;
@@ -1338,7 +1366,7 @@ namespace System
}
// Get the daylight changes for the year of the specified time.
- DaylightTimeStruct daylightTime = zone.GetDaylightTime(year, rule);
+ DaylightTimeStruct daylightTime = zone.GetDaylightTime(year, rule, ruleIndex);
// The start and end times represent the range of universal times that are in DST for that year.
// Within that there is an ambiguous hour, usually right at the end, but at the beginning in
@@ -1352,14 +1380,20 @@ namespace System
// Note we handle the similar case when rule year start with daylight saving and previous year end with daylight saving.
bool ignoreYearAdjustment = false;
- TimeSpan dstStartOffset = zone.GetDaylightSavingsStartOffsetFromUtc(utc, rule);
+ TimeSpan dstStartOffset = zone.GetDaylightSavingsStartOffsetFromUtc(utc, rule, ruleIndex);
DateTime startTime;
if (rule.IsStartDateMarkerForBeginningOfYear() && daylightTime.Start.Year > DateTime.MinValue.Year)
{
- AdjustmentRule previousYearRule = zone.GetAdjustmentRuleForTime(new DateTime(daylightTime.Start.Year - 1, 12, 31));
+ int? previousYearRuleIndex;
+ AdjustmentRule previousYearRule = zone.GetAdjustmentRuleForTime(
+ new DateTime(daylightTime.Start.Year - 1, 12, 31),
+ out previousYearRuleIndex);
if (previousYearRule != null && previousYearRule.IsEndDateMarkerForEndOfYear())
{
- DaylightTimeStruct previousDaylightTime = zone.GetDaylightTime(daylightTime.Start.Year - 1, previousYearRule);
+ DaylightTimeStruct previousDaylightTime = zone.GetDaylightTime(
+ daylightTime.Start.Year - 1,
+ previousYearRule,
+ previousYearRuleIndex);
startTime = previousDaylightTime.Start - utc - previousYearRule.BaseUtcOffsetDelta;
ignoreYearAdjustment = true;
}
@@ -1377,7 +1411,10 @@ namespace System
DateTime endTime;
if (rule.IsEndDateMarkerForEndOfYear() && daylightTime.End.Year < DateTime.MaxValue.Year)
{
- AdjustmentRule nextYearRule = zone.GetAdjustmentRuleForTime(new DateTime(daylightTime.End.Year + 1, 1, 1));
+ int? nextYearRuleIndex;
+ AdjustmentRule nextYearRule = zone.GetAdjustmentRuleForTime(
+ new DateTime(daylightTime.End.Year + 1, 1, 1),
+ out nextYearRuleIndex);
if (nextYearRule != null && nextYearRule.IsStartDateMarkerForBeginningOfYear())
{
if (nextYearRule.IsEndDateMarkerForEndOfYear())
@@ -1387,7 +1424,10 @@ namespace System
}
else
{
- DaylightTimeStruct nextdaylightTime = zone.GetDaylightTime(daylightTime.End.Year + 1, nextYearRule);
+ DaylightTimeStruct nextdaylightTime = zone.GetDaylightTime(
+ daylightTime.End.Year + 1,
+ nextYearRule,
+ nextYearRuleIndex);
endTime = nextdaylightTime.End - utc - nextYearRule.BaseUtcOffsetDelta - nextYearRule.DaylightDelta;
}
ignoreYearAdjustment = true;
@@ -1644,14 +1684,15 @@ namespace System
private static TimeSpan GetUtcOffset(DateTime time, TimeZoneInfo zone, TimeZoneInfoOptions flags)
{
TimeSpan baseOffset = zone.BaseUtcOffset;
- AdjustmentRule rule = zone.GetAdjustmentRuleForTime(time);
+ int? ruleIndex;
+ AdjustmentRule rule = zone.GetAdjustmentRuleForTime(time, out ruleIndex);
if (rule != null)
{
baseOffset = baseOffset + rule.BaseUtcOffsetDelta;
if (rule.HasDaylightSaving)
{
- DaylightTimeStruct daylightTime = zone.GetDaylightTime(time.Year, rule);
+ DaylightTimeStruct daylightTime = zone.GetDaylightTime(time.Year, rule, ruleIndex);
bool isDaylightSavings = GetIsDaylightSavings(time, rule, daylightTime, flags);
baseOffset += (isDaylightSavings ? rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */);
}
@@ -1690,21 +1731,24 @@ namespace System
isAmbiguousLocalDst = false;
TimeSpan baseOffset = zone.BaseUtcOffset;
int year;
+ int? ruleIndex;
AdjustmentRule rule;
if (time > s_maxDateOnly)
{
- rule = zone.GetAdjustmentRuleForTime(DateTime.MaxValue);
+ rule = zone.GetAdjustmentRuleForTime(DateTime.MaxValue, out ruleIndex);
year = 9999;
}
else if (time < s_minDateOnly)
{
- rule = zone.GetAdjustmentRuleForTime(DateTime.MinValue);
+ rule = zone.GetAdjustmentRuleForTime(DateTime.MinValue, out ruleIndex);
year = 1;
}
else
{
- rule = zone.GetAdjustmentRuleForTime(time, dateTimeisUtc: true);
+ rule = zone.GetAdjustmentRuleForTime(time, dateTimeisUtc: true, ruleIndex: out ruleIndex);
+ Debug.Assert(rule == null || ruleIndex.HasValue,
+ "If GetAdjustmentRuleForTime returned an AdjustmentRule, ruleIndex should also be set.");
// As we get the associated rule using the adjusted targetTime, we should use the adjusted year (targetTime.Year) too as after adding the baseOffset,
// sometimes the year value can change if the input datetime was very close to the beginning or the end of the year. Examples of such cases:
@@ -1719,7 +1763,7 @@ namespace System
baseOffset = baseOffset + rule.BaseUtcOffsetDelta;
if (rule.HasDaylightSaving)
{
- isDaylightSavings = GetIsDaylightSavingsFromUtc(time, year, zone._baseUtcOffset, rule, out isAmbiguousLocalDst, zone);
+ isDaylightSavings = GetIsDaylightSavingsFromUtc(time, year, zone._baseUtcOffset, rule, ruleIndex, out isAmbiguousLocalDst, zone);
baseOffset += (isDaylightSavings ? rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */);
}
}