Skip to content

Commit

Permalink
Address PR feedback, and use allows ref struct APIs in some more places
Browse files Browse the repository at this point in the history
  • Loading branch information
stephentoub committed May 31, 2024
1 parent 3ebbad9 commit 78385ca
Show file tree
Hide file tree
Showing 16 changed files with 191 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ public static object GetUninitializedObject(
/// <returns>true if given type is reference type or value type that contains references</returns>
[Intrinsic]
public static bool IsReferenceOrContainsReferences<T>()
where T : allows ref struct
// where T : allows ref struct // TODO https://github.com/dotnet/runtime/issues/102847
{
// The body of this function will be replaced by the EE with unsafe code!!!
// See getILIntrinsicImplementationForRuntimeHelpers for how this happens.
Expand Down Expand Up @@ -787,7 +787,6 @@ public bool IsTypeDesc

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TypeHandle TypeHandleOf<T>()
where T : allows ref struct
{
return new TypeHandle((void*)RuntimeTypeHandle.ToIntPtr(typeof(T).TypeHandle));
}
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Linq/src/System/Linq/Sum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ private static TResult Sum<T, TResult>(ReadOnlySpan<T> span)

if (typeof(T) == typeof(long))
{
return (TResult)(object)SumSignedIntegersVectorized(MemoryMarshal.Cast<T, long>(span));
return (TResult)(object)SumSignedIntegersVectorized(Unsafe.BitCast<ReadOnlySpan<T>, ReadOnlySpan<long>>(span));
}
if (typeof(T) == typeof(int))
{
return (TResult)(object)SumSignedIntegersVectorized(MemoryMarshal.Cast<T, int>(span));
return (TResult)(object)SumSignedIntegersVectorized(Unsafe.BitCast<ReadOnlySpan<T>, ReadOnlySpan<int>>(span));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ private static void ValidateInputOutputSpanNonOverlapping<T>(ReadOnlySpan<T> inp
private static unsafe Span<TTo> Rename<TFrom, TTo>(Span<TFrom> span)
{
Debug.Assert(sizeof(TFrom) == sizeof(TTo));
#if NET9_0_OR_GREATER
return Unsafe.BitCast<Span<TFrom>, Span<TTo>>(span);
#else
return *(Span<TTo>*)(&span);
#endif
}

/// <summary>Creates a span of <typeparamref name="TTo"/> from a <typeparamref name="TFrom"/> when they're the same type.</summary>
Expand All @@ -48,7 +52,11 @@ private static unsafe Span<TTo> Rename<TFrom, TTo>(Span<TFrom> span)
private static unsafe ReadOnlySpan<TTo> Rename<TFrom, TTo>(ReadOnlySpan<TFrom> span)
{
Debug.Assert(sizeof(TFrom) == sizeof(TTo));
#if NET9_0_OR_GREATER
return Unsafe.BitCast<ReadOnlySpan<TFrom>, ReadOnlySpan<TTo>>(span);
#else
return *(ReadOnlySpan<TTo>*)(&span);
#endif
}

/// <summary>Mask used to handle alignment elements before vectorized handling of the input.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ namespace System.Collections.Generic
/// <summary>Exposes an enumerator that provides asynchronous iteration over values of a specified type.</summary>
/// <typeparam name="T">The type of values to enumerate.</typeparam>
public interface IAsyncEnumerable<out T>
#if NET9_0_OR_GREATER
where T : allows ref struct
#endif
{
/// <summary>Returns an enumerator that iterates asynchronously through the collection.</summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that may be used to cancel the asynchronous iteration.</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ namespace System.Collections.Generic
/// <summary>Supports a simple asynchronous iteration over a generic collection.</summary>
/// <typeparam name="T">The type of objects to enumerate.</typeparam>
public interface IAsyncEnumerator<out T> : IAsyncDisposable
#if NET9_0_OR_GREATER
where T : allows ref struct
#endif
{
/// <summary>Advances the enumerator asynchronously to the next element of the collection.</summary>
/// <returns>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -763,12 +763,12 @@ private static void AppendString<TChar>(ref ValueListBuilder<TChar> result, scop
{
if (typeof(TChar) == typeof(char))
{
result.Append(MemoryMarshal.Cast<char, TChar>(s));
result.Append(Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(s));
}
else
{
Debug.Assert(typeof(TChar) == typeof(byte));
Encoding.UTF8.GetBytes(s, MemoryMarshal.Cast<TChar, byte>(result.AppendSpan(Encoding.UTF8.GetByteCount(s))));
Encoding.UTF8.GetBytes(s, Unsafe.BitCast<Span<TChar>, Span<byte>>(result.AppendSpan(Encoding.UTF8.GetByteCount(s))));
}
}

Expand All @@ -777,8 +777,8 @@ internal static void FormatFraction<TChar>(ref ValueListBuilder<TChar> result, i
Span<TChar> chars = stackalloc TChar[11];
int charCount;
bool formatted = typeof(TChar) == typeof(char) ?
fraction.TryFormat(MemoryMarshal.Cast<TChar, char>(chars), out charCount, fractionFormat, CultureInfo.InvariantCulture) :
fraction.TryFormat(MemoryMarshal.Cast<TChar, byte>(chars), out charCount, fractionFormat, CultureInfo.InvariantCulture);
fraction.TryFormat(Unsafe.BitCast<Span<TChar>, Span<char>>(chars), out charCount, fractionFormat, CultureInfo.InvariantCulture) :
fraction.TryFormat(Unsafe.BitCast<Span<TChar>, Span<byte>>(chars), out charCount, fractionFormat, CultureInfo.InvariantCulture);
Debug.Assert(charCount != 0);
result.Append(chars.Slice(0, charCount));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,8 @@ internal ReadOnlySpan<TChar> AMDesignatorTChar<TChar>() where TChar : unmanaged,
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(AMDesignator) :
MemoryMarshal.Cast<byte, TChar>(amDesignatorUtf8 ??= Encoding.UTF8.GetBytes(AMDesignator));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(AMDesignator) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(amDesignatorUtf8 ??= Encoding.UTF8.GetBytes(AMDesignator));
}

public Calendar Calendar
Expand Down Expand Up @@ -607,8 +607,8 @@ internal ReadOnlySpan<TChar> DateSeparatorTChar<TChar>() where TChar : unmanaged
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(DateSeparator) :
MemoryMarshal.Cast<byte, TChar>(dateSeparatorUtf8 ??= Encoding.UTF8.GetBytes(DateSeparator));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(DateSeparator) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(dateSeparatorUtf8 ??= Encoding.UTF8.GetBytes(DateSeparator));
}

public DayOfWeek FirstDayOfWeek
Expand Down Expand Up @@ -810,8 +810,8 @@ internal ReadOnlySpan<TChar> PMDesignatorTChar<TChar>() where TChar : unmanaged,
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(PMDesignator) :
MemoryMarshal.Cast<byte, TChar>(pmDesignatorUtf8 ??= Encoding.UTF8.GetBytes(PMDesignator));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(PMDesignator) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(pmDesignatorUtf8 ??= Encoding.UTF8.GetBytes(PMDesignator));
}

public string RFC1123Pattern => rfc1123Pattern;
Expand Down Expand Up @@ -992,8 +992,8 @@ internal ReadOnlySpan<TChar> TimeSeparatorTChar<TChar>() where TChar : unmanaged
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(TimeSeparator) :
MemoryMarshal.Cast<byte, TChar>(timeSeparatorUtf8 ??= Encoding.UTF8.GetBytes(TimeSeparator));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(TimeSeparator) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(timeSeparatorUtf8 ??= Encoding.UTF8.GetBytes(TimeSeparator));
}

public string UniversalSortableDateTimePattern => universalSortableDateTimePattern;
Expand Down Expand Up @@ -1731,8 +1731,8 @@ internal ReadOnlySpan<TChar> DecimalSeparatorTChar<TChar>() where TChar : unmana
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(DecimalSeparator) :
MemoryMarshal.Cast<byte, TChar>(_decimalSeparatorUtf8 ??= Encoding.UTF8.GetBytes(DecimalSeparator));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(DecimalSeparator) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_decimalSeparatorUtf8 ??= Encoding.UTF8.GetBytes(DecimalSeparator));
}

// Positive TimeSpan Pattern
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,8 @@ internal ReadOnlySpan<TChar> CurrencyDecimalSeparatorTChar<TChar>() where TChar
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_currencyDecimalSeparator) :
MemoryMarshal.Cast<byte, TChar>(_currencyDecimalSeparatorUtf8 ??= Encoding.UTF8.GetBytes(_currencyDecimalSeparator));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_currencyDecimalSeparator) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_currencyDecimalSeparatorUtf8 ??= Encoding.UTF8.GetBytes(_currencyDecimalSeparator));
}

public bool IsReadOnly => _isReadOnly;
Expand Down Expand Up @@ -361,8 +361,8 @@ internal ReadOnlySpan<TChar> CurrencyGroupSeparatorTChar<TChar>() where TChar :
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_currencyGroupSeparator) :
MemoryMarshal.Cast<byte, TChar>(_currencyGroupSeparatorUtf8 ??= Encoding.UTF8.GetBytes(_currencyGroupSeparator));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_currencyGroupSeparator) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_currencyGroupSeparatorUtf8 ??= Encoding.UTF8.GetBytes(_currencyGroupSeparator));
}

public string CurrencySymbol
Expand All @@ -383,8 +383,8 @@ internal ReadOnlySpan<TChar> CurrencySymbolTChar<TChar>() where TChar : unmanage
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_currencySymbol) :
MemoryMarshal.Cast<byte, TChar>(_currencySymbolUtf8 ??= Encoding.UTF8.GetBytes(_currencySymbol));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_currencySymbol) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_currencySymbolUtf8 ??= Encoding.UTF8.GetBytes(_currencySymbol));
}

internal byte[]? CurrencySymbolUtf8 => _currencySymbolUtf8 ??= Encoding.UTF8.GetBytes(_currencySymbol);
Expand Down Expand Up @@ -429,8 +429,8 @@ internal ReadOnlySpan<TChar> NaNSymbolTChar<TChar>() where TChar : unmanaged, IU
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_nanSymbol) :
MemoryMarshal.Cast<byte, TChar>(_nanSymbolUtf8 ??= Encoding.UTF8.GetBytes(_nanSymbol));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_nanSymbol) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_nanSymbolUtf8 ??= Encoding.UTF8.GetBytes(_nanSymbol));
}

public int CurrencyNegativePattern
Expand Down Expand Up @@ -514,8 +514,8 @@ internal ReadOnlySpan<TChar> NegativeInfinitySymbolTChar<TChar>() where TChar :
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_negativeInfinitySymbol) :
MemoryMarshal.Cast<byte, TChar>(_negativeInfinitySymbolUtf8 ??= Encoding.UTF8.GetBytes(_negativeInfinitySymbol));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_negativeInfinitySymbol) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_negativeInfinitySymbolUtf8 ??= Encoding.UTF8.GetBytes(_negativeInfinitySymbol));
}

public string NegativeSign
Expand All @@ -537,8 +537,8 @@ internal ReadOnlySpan<TChar> NegativeSignTChar<TChar>() where TChar : unmanaged,
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_negativeSign) :
MemoryMarshal.Cast<byte, TChar>(_negativeSignUtf8 ??= Encoding.UTF8.GetBytes(_negativeSign));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_negativeSign) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_negativeSignUtf8 ??= Encoding.UTF8.GetBytes(_negativeSign));
}

public int NumberDecimalDigits
Expand Down Expand Up @@ -573,8 +573,8 @@ internal ReadOnlySpan<TChar> NumberDecimalSeparatorTChar<TChar>() where TChar :
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_numberDecimalSeparator) :
MemoryMarshal.Cast<byte, TChar>(_numberDecimalSeparatorUtf8 ??= Encoding.UTF8.GetBytes(_numberDecimalSeparator));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_numberDecimalSeparator) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_numberDecimalSeparatorUtf8 ??= Encoding.UTF8.GetBytes(_numberDecimalSeparator));
}

public string NumberGroupSeparator
Expand All @@ -594,8 +594,8 @@ internal ReadOnlySpan<TChar> NumberGroupSeparatorTChar<TChar>() where TChar : un
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_numberGroupSeparator) :
MemoryMarshal.Cast<byte, TChar>(_numberGroupSeparatorUtf8 ??= Encoding.UTF8.GetBytes(_numberGroupSeparator));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_numberGroupSeparator) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_numberGroupSeparatorUtf8 ??= Encoding.UTF8.GetBytes(_numberGroupSeparator));
}

public int CurrencyPositivePattern
Expand Down Expand Up @@ -631,8 +631,8 @@ internal ReadOnlySpan<TChar> PositiveInfinitySymbolTChar<TChar>() where TChar :
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_positiveInfinitySymbol) :
MemoryMarshal.Cast<byte, TChar>(_positiveInfinitySymbolUtf8 ??= Encoding.UTF8.GetBytes(_positiveInfinitySymbol));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_positiveInfinitySymbol) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_positiveInfinitySymbolUtf8 ??= Encoding.UTF8.GetBytes(_positiveInfinitySymbol));
}

public string PositiveSign
Expand All @@ -654,8 +654,8 @@ internal ReadOnlySpan<TChar> PositiveSignTChar<TChar>() where TChar : unmanaged,
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_positiveSign) :
MemoryMarshal.Cast<byte, TChar>(_positiveSignUtf8 ??= Encoding.UTF8.GetBytes(_positiveSign));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_positiveSign) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_positiveSignUtf8 ??= Encoding.UTF8.GetBytes(_positiveSign));
}

public int PercentDecimalDigits
Expand Down Expand Up @@ -690,8 +690,8 @@ internal ReadOnlySpan<TChar> PercentDecimalSeparatorTChar<TChar>() where TChar :
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_percentDecimalSeparator) :
MemoryMarshal.Cast<byte, TChar>(_percentDecimalSeparatorUtf8 ??= Encoding.UTF8.GetBytes(_percentDecimalSeparator));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_percentDecimalSeparator) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_percentDecimalSeparatorUtf8 ??= Encoding.UTF8.GetBytes(_percentDecimalSeparator));
}

public string PercentGroupSeparator
Expand All @@ -711,8 +711,8 @@ internal ReadOnlySpan<TChar> PercentGroupSeparatorTChar<TChar>() where TChar : u
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_percentGroupSeparator) :
MemoryMarshal.Cast<byte, TChar>(_percentGroupSeparatorUtf8 ??= Encoding.UTF8.GetBytes(_percentGroupSeparator));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_percentGroupSeparator) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_percentGroupSeparatorUtf8 ??= Encoding.UTF8.GetBytes(_percentGroupSeparator));
}

public string PercentSymbol
Expand All @@ -732,8 +732,8 @@ internal ReadOnlySpan<TChar> PercentSymbolTChar<TChar>() where TChar : unmanaged
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_percentSymbol) :
MemoryMarshal.Cast<byte, TChar>(_percentSymbolUtf8 ??= Encoding.UTF8.GetBytes(_percentSymbol));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_percentSymbol) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_percentSymbolUtf8 ??= Encoding.UTF8.GetBytes(_percentSymbol));
}

public string PerMilleSymbol
Expand All @@ -754,8 +754,8 @@ internal ReadOnlySpan<TChar> PerMilleSymbolTChar<TChar>() where TChar : unmanage
{
Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
return typeof(TChar) == typeof(char) ?
MemoryMarshal.Cast<char, TChar>(_perMilleSymbol) :
MemoryMarshal.Cast<byte, TChar>(_perMilleSymbolUtf8 ??= Encoding.UTF8.GetBytes(_perMilleSymbol));
Unsafe.BitCast<ReadOnlySpan<char>, ReadOnlySpan<TChar>>(_perMilleSymbol) :
Unsafe.BitCast<ReadOnlySpan<byte>, ReadOnlySpan<TChar>>(_perMilleSymbolUtf8 ??= Encoding.UTF8.GetBytes(_perMilleSymbol));
}

public string[] NativeDigits
Expand Down
Loading

0 comments on commit 78385ca

Please sign in to comment.